Skip to content

Commit

Permalink
Merge pull request #14 from wraith4081/global-functions
Browse files Browse the repository at this point in the history
Global Functions - Development Progress 3
  • Loading branch information
wraith4081 authored Aug 16, 2023
2 parents 139f5f1 + 1c75ab2 commit dd03021
Show file tree
Hide file tree
Showing 11 changed files with 873 additions and 23 deletions.
8 changes: 0 additions & 8 deletions src/example/test.wrsc

This file was deleted.

17 changes: 17 additions & 0 deletions src/example/test.ws
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
let a = 5419351;
let b = 1725033;

let pione = a / b;
let pitwo = 9801 / (2206 * SQRTTWO);
let three = 20 * atan(1 / 7) + 8 * atan(3 / 79);

let obj = {
pi: {
one: pione,
two: pitwo,
three
},
PI
};

print(obj)
23 changes: 21 additions & 2 deletions src/frontend/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,27 @@ export function tokenize(sourceCode: string): Token[] {
tokens.push(token(src.shift()!, TokenType.OpenBracket));
} else if (src[0] === ']') {
tokens.push(token(src.shift()!, TokenType.CloseBracket));
} else if (['+', '-', '*', '/', '%'].includes(src[0])) {
tokens.push(token(src.shift()!, TokenType.BinaryOperator));
} else if (['+', '-', '*', '/', '%', '&', '|', '^', '~', '<', '>'].includes(src[0])) {

if (
src[0] === '<' &&
src[1] === '<'
) {
tokens.push(token(src.shift()! + src.shift()!, TokenType.BinaryOperator));
} else if (
src[0] === '>' &&
src[1] === '>'
) {
if (
src[2] === '>'
) {
tokens.push(token(src.shift()! + src.shift()! + src.shift()!, TokenType.BinaryOperator));
} else {
tokens.push(token(src.shift()! + src.shift()!, TokenType.BinaryOperator));
}
} else {
tokens.push(token(src.shift()!, TokenType.BinaryOperator));
}
} else if (src[0] === '=') {
tokens.push(token(src.shift()!, TokenType.Equals));
} else if (src[0] === ';') {
Expand Down
28 changes: 26 additions & 2 deletions src/frontend/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default class Parser {
* @returns The parsed assignment expression.
*/
private parseAssignmentExpression(): Expression {
const left = this.parseObjectExpression(); // TODO: Switch this into ObjectExpression
const left = this.parseObjectExpression();

if (this.at().type === TokenType.Equals) {
this.eatToken(); // Advance past the '='
Expand Down Expand Up @@ -229,7 +229,7 @@ export default class Parser {
private parseMultiplicativeExpression(): Expression {
let left = this.parseCallMemberExpression();

while (['/', '*', '%'].includes(this.at().value)) {
while (['-', '+', '/', '*', '%', '&', '|', '^', '~', '<<', '>>', '>>'].includes(this.at().value)) {
const operator = this.eatToken().value;
const right = this.parseCallMemberExpression();

Expand All @@ -244,6 +244,11 @@ export default class Parser {
return left;
}

/**
* Parses a member expression, which can be either a property access or an array access.
* @returns The parsed expression.
* @throws An error if the expression is invalid.
*/
private parseCallMemberExpression(): Expression {
const member = this.parseMemberExpression();

Expand All @@ -254,6 +259,11 @@ export default class Parser {
return member;
}

/**
* Parses a function call expression.
* @param caller The expression that represents the function being called.
* @returns The parsed expression.
*/
private parseCallExpression(caller: Expression): Expression {
let callerExpression = {
kind: 'CallExpression',
Expand All @@ -268,6 +278,10 @@ export default class Parser {
return callerExpression;
}

/**
* Parses a list of function arguments.
* @returns An array of parsed argument expressions.
*/
private parseArguments(): Expression[] {
this.except(TokenType.OpenParentesis, "Unexpected token founded inside arguments list. Expected opening parentesis");

Expand All @@ -278,6 +292,11 @@ export default class Parser {
return args;
}

/**
* Parses a member expression, which can be either a property access or an array access.
* @returns The parsed expression.
* @throws An error if the expression is invalid.
*/
private parseArgumentsList(): Expression[] {
const args = [this.parseAssignmentExpression()];

Expand All @@ -289,6 +308,11 @@ export default class Parser {
return args;
}

/**
* Parses a member expression, which can be either a property access or an array access.
* @returns The parsed expression.
* @throws An error if the expression is invalid.
*/
private parseMemberExpression(): Expression {
let object: Expression = this.parsePrimaryExpression();

Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function run(filename: string) {

// Evaluate the AST and print the result
const result = evaluate(program, env);
console.log(result);
// console.log(result);

// Exit with a status code of 0
process.exit(0);
Expand Down
34 changes: 30 additions & 4 deletions src/runtime/environment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import {
floor, ceil, round, abs, acos, acosh, asin, asinh,
atan, atanh, cbrt, clztt, cos, cosh, exp, expm,
fround, log, logten, logonep, logtwo, hypot, sign, sin,
sinh, sqrt, tan, tanh, trunc, /*potwo,*/ imul, pow,
max, min, random, listmax, listmin, sum, avg,

Euler, LNTEN, LNTWO, LOGTWOE,
LOGTENE, PI, SQRTONETWO, SQRTTWO
} from "./functions/math";
import { warn } from "./log";
import { MK_BOOL, MK_NULL, RuntimeValue } from "./values";

import { MK_BOOL, MK_NATIVE_FUNCTION, MK_NULL, MK_NUMBER, NumberValue, RuntimeValue } from "./values";
/**
* Creates a new global environment with pre-defined values for true, false, and null.
* @returns The new global environment.
Expand All @@ -11,8 +20,25 @@ export function createGlobalEnvironment() {
Object.entries({
'true': MK_BOOL(true),
'false': MK_BOOL(false),
'null': MK_NULL()
}).forEach(key => env.declare(...key));
'null': MK_NULL(),

'print': MK_NATIVE_FUNCTION((args, scope) => {

console.log(...args);

return MK_NULL();
}),

floor, ceil, round, abs, acos, acosh, asin, asinh,
atan, atanh, cbrt, clztt, cos, cosh, exp, expm,
fround, log, logten, logonep, logtwo, hypot, sign, sin,
sinh, sqrt, tan, tanh, trunc, /*potwo,*/ imul, pow,
max, min, random, listmax, listmin, sum, avg,

Euler, LNTEN, LNTWO, LOGTENE,
LOGTWOE, PI, SQRTONETWO, SQRTTWO

}).forEach(key => env.declare(...key as [any, any]));

return env;
}
Expand Down
36 changes: 34 additions & 2 deletions src/runtime/eval/expressions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AssignmentExpression, BinaryExpression, Identifier, ObjectLiteral } from "../../frontend/ast";
import { AssignmentExpression, BinaryExpression, CallExpression, Identifier, ObjectLiteral } from "../../frontend/ast";
import Environment from "../environment";
import { evaluate } from "../interpreter";
import { MK_NULL, NumberValue, ObjectValue, RuntimeValue } from "../values";
import { error } from "../log";
import { MK_NULL, NativeFunctionValue, NumberValue, ObjectValue, RuntimeValue } from "../values";

/**
* Evaluates a binary expression with two numeric operands and returns a numeric value.
Expand All @@ -19,6 +20,13 @@ function evaluateNumericBinaryExpression(lhs: NumberValue, rhs: NumberValue, ope
case '*': value = lhs.value * rhs.value; break;
case '/': value = lhs.value / rhs.value; break;
case '%': value = lhs.value % rhs.value; break;
case '&': value = lhs.value & rhs.value; break;
case '|': value = lhs.value | rhs.value; break;
case '^': value = lhs.value ^ rhs.value; break;
// case '~': value = ~lhs.value; break;
case '<<': value = lhs.value << rhs.value; break;
case '>>': value = lhs.value >> rhs.value; break;
case '>>>': value = lhs.value >>> rhs.value; break;
default: {
console.error('This binary operator has not yet been setup for interplation.', operator);
process.exit(1);
Expand Down Expand Up @@ -101,3 +109,27 @@ export function evaluateObjectExpression(node: ObjectLiteral, env: Environment):

return object;
}

/**
* Evaluates a function call expression.
* @param expr The expression to evaluate.
* @param env The environment in which to evaluate the expression.
* @returns The result of the function call.
* @throws An error if the function is not a native function.
*/
export function evaluateCallExpression(
expr: CallExpression,
env: Environment
) {
const args = expr.args.map(arg => evaluate(arg, env));
const fn = evaluate(expr.caller, env) as NativeFunctionValue;

if (fn.type !== "native-function") {
error(`Cannot call non-function value. Got "${fn.type}" instead.`);
process.exit(1);
}

const result = fn?.call?.(args, env);

return result
}
Loading

0 comments on commit dd03021

Please sign in to comment.