Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Commit

Permalink
function returns
Browse files Browse the repository at this point in the history
  • Loading branch information
eoussama committed Mar 17, 2024
1 parent fb254b8 commit 77370ba
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 9 deletions.
9 changes: 6 additions & 3 deletions scripts/functions.nkm
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
hear me out multiplicator is 5;

let me cook multiply(x) {
multiplicator * x;
reda multiplicator * x;
}

a sa7 hear me out result is multiply(2);
let me cook print(message) {
loncina(message);
}

loncina("result: ", 2, " * ", multiplicator, " = ", result);
a sa7 hear me out retResult is multiply(2);
print("ret result: " + bait(2) + " * " + bait(multiplicator) + " = " + bait(retResult))
34 changes: 31 additions & 3 deletions src/core/helpers/runtime.helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TPrimitive } from '../types/primitive.type';
import { TFunctionCall } from '../types/function.type';
import { INativeFunctionVal } from '../types/runtime-values.type';
import { IBoolVal, INullVal, INumberVal, IStringVal, ISkipVal, Type } from '..';
import { INativeFunctionVal, IRuntimeVal } from '../types/runtime-values.type';
import { IBooleanVal, INullVal, INumberVal, IStringVal, ISkipVal, Type } from '..';



Expand All @@ -10,6 +11,33 @@ import { IBoolVal, INullVal, INumberVal, IStringVal, ISkipVal, Type } from '..';
*/
export class RuntimeHelper {

public static createValue(value: TPrimitive): IRuntimeVal {
let type: Type;

switch (typeof value) {
case 'number': {
type = Type.Number;
break;
}

case 'boolean': {
type = Type.Boolean;
break;
}

case 'string': {
type = Type.String;
break;
}

default: {
type = Type.Null;
}
}

return { type, value } as IRuntimeVal;
}

/**
* @description
* Creates a null value
Expand Down Expand Up @@ -52,7 +80,7 @@ export class RuntimeHelper {
*
* @param boolean The boolean value
*/
public static createBoolean(boolean: boolean): IBoolVal {
public static createBoolean(boolean: boolean): IBooleanVal {
return { type: Type.Boolean, value: boolean };
}

Expand Down
5 changes: 5 additions & 0 deletions src/core/types/ast.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export interface IProgramNode extends IStatementNode {
body: Array<IStatementNode>;
}

export interface IReturnNode extends IStatementNode {
kind: NodeType.Return;
value: IExpressionNode;
}

export interface IVariableDeclarationNode extends IStatementNode {
kind: NodeType.VariableDeclaration;
constant: boolean;
Expand Down
24 changes: 23 additions & 1 deletion src/frontend/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MissingEqualsError, MissingIdentifierError, MissingDotError, UnclosedPa

import { TToken } from '../core/types/token.type';
import { TOnErrorCallbackFn } from '../core/types/on-error-callback.type';
import { IAssignmentNode, IBinaryExpression, ICallNode, IExpressionNode, IFunctionDeclarationNode, IIdentifierNode, INumberNode, IProgramNode, ISkipNode, IStatementNode, IStringNode, IVariableDeclarationNode } from '../core/types/ast.type';
import { IAssignmentNode, IBinaryExpression, ICallNode, IExpressionNode, IFunctionDeclarationNode, IIdentifierNode, INumberNode, IProgramNode, IReturnNode, ISkipNode, IStatementNode, IStringNode, IVariableDeclarationNode } from '../core/types/ast.type';

import { Consumer } from './consumer';

Expand Down Expand Up @@ -42,6 +42,10 @@ export class Parser extends Consumer<TToken> {
*/
private parseStatement(): IStatementNode {
switch (this.at().type) {
case TokenType.Return: {
return this.parseReturn();
}

case TokenType.Let:
case TokenType.Const: {
return this.parseVariableDeclaration();
Expand Down Expand Up @@ -364,6 +368,24 @@ export class Parser extends Consumer<TToken> {
return fn;
}

/**
* @description
* Parses the return statement
*/
private parseReturn(): IStatementNode {
const returnToken = this.eat();
const valueExpression = this.parseExpression();

this.expect(TokenType.Semicolon, new MissingDotError(valueExpression.end));

return {
kind: NodeType.Return,
value: valueExpression,
end: valueExpression.end,
start: returnToken?.location
} as IReturnNode;
}

/**
* @description
* Parses a list of tokens into an AST
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ export class Environment {

return RuntimeHelper.createNull();
}), true);

this.declareVariable('bait', RuntimeHelper.createFunction(args => {
const value = (args[0] as IStringVal).value ?? 'bruh';
return RuntimeHelper.createString(value.toString());
}), true);
}

/**
Expand Down
27 changes: 25 additions & 2 deletions src/runtime/interpreter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NodeType } from '../core/enums/node-type.enum';

import { IFunctionVal, INativeFunctionVal, INumberVal, IRuntimeVal, IStringVal } from '../core/types/runtime-values.type';
import { IAssignmentNode, IBinaryExpression, ICallNode, IFunctionDeclarationNode, IIdentifierNode, INumberNode, IProgramNode, IStatementNode, IStringNode, IVariableDeclarationNode } from '../core/types/ast.type';
import { IAssignmentNode, IBinaryExpression, ICallNode, IFunctionDeclarationNode, IIdentifierNode, INumberNode, IProgramNode, IReturnNode, IStatementNode, IStringNode, IVariableDeclarationNode } from '../core/types/ast.type';

import { Environment } from './environment';
import { RuntimeHelper } from '../core/helpers/runtime.helper';
Expand Down Expand Up @@ -184,15 +184,22 @@ export class Evaluator {
scope.declareVariable(varName, varValue);
}

// @ts-ignore
let hasReturn: boolean = false;
let result: IRuntimeVal = RuntimeHelper.createNull();

for (const statement of func.body) {
if (statement.kind !== NodeType.Skip) {
result = this.evaluate(statement, scope);

if (statement.kind === NodeType.Return) {
hasReturn = true;
break;
}
}
}

return result;
return hasReturn ? result : RuntimeHelper.createNull();
}

env.errorManager?.raise(new InvalidFunctionError(call.start));
Expand All @@ -216,6 +223,18 @@ export class Evaluator {
return env.assignVariable(name, this.evaluate(node.value, env));
}

/**
* @description
* Evaluates a return statement
*
* @param node The return statement
* @param env The scope of evaluation
*/
private evaluateReturn(node: IReturnNode, env: Environment): IRuntimeVal {
const val = this.evaluate(node.value, env) as IStringVal;
return RuntimeHelper.createValue(val.value);
}

/**
* @description
* Evaluates an AST tree
Expand Down Expand Up @@ -265,6 +284,10 @@ export class Evaluator {
return RuntimeHelper.createSkip();
}

case NodeType.Return: {
return this.evaluateReturn(node as IReturnNode, env);
}

default: {
env.errorManager?.raise(new UnrecognizedStatementError(node.start));
return RuntimeHelper.createNull();
Expand Down

0 comments on commit 77370ba

Please sign in to comment.