First commit for CG
This commit is contained in:
commit
d60e5aa29f
11 changed files with 1397 additions and 0 deletions
34
src/ast.ts
Normal file
34
src/ast.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import type { Value } from './types';
|
||||
|
||||
export type Literal = {
|
||||
kind: 'literal'
|
||||
value: Value
|
||||
}
|
||||
|
||||
export type BinaryOp = {
|
||||
kind: 'binaryop'
|
||||
operator: string
|
||||
left: AST
|
||||
right: AST
|
||||
}
|
||||
|
||||
export type Variable = {
|
||||
kind: 'variable'
|
||||
name: string
|
||||
}
|
||||
|
||||
export type Let = {
|
||||
kind: 'let'
|
||||
name: string
|
||||
value: AST
|
||||
body: AST
|
||||
}
|
||||
|
||||
export type If = {
|
||||
kind: 'if'
|
||||
condition: AST
|
||||
then: AST
|
||||
else: AST
|
||||
}
|
||||
|
||||
export type AST = Literal | BinaryOp | Variable | Let | If
|
||||
3
src/env.ts
Normal file
3
src/env.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import type { Value } from './types';
|
||||
|
||||
export type Env = Map<string, Value>
|
||||
64
src/interpreter.ts
Normal file
64
src/interpreter.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import type { AST } from './ast';
|
||||
import type { Env } from './env';
|
||||
import type { Value } from './types';
|
||||
|
||||
export function evaluate(ast: AST, env: Env): Value {
|
||||
switch (ast.kind) {
|
||||
case 'literal':
|
||||
return ast.value;
|
||||
|
||||
case 'variable':
|
||||
const val = env.get(ast.name);
|
||||
if (val === undefined)
|
||||
throw new Error(`Unknown variable: ${ast.name}`);
|
||||
return val;
|
||||
|
||||
case 'binaryop':
|
||||
const left = evaluate(ast.left, env);
|
||||
const right = evaluate(ast.right, env);
|
||||
return evaluateBinaryOp(ast.operator, left, right);
|
||||
|
||||
case 'let':
|
||||
const val2 = evaluate(ast.value, env);
|
||||
const newEnv = new Map(env).set(ast.name, val2);
|
||||
return evaluate(ast.body, newEnv);
|
||||
|
||||
case 'if':
|
||||
const { kind, value } = evaluate(ast.condition, env);
|
||||
|
||||
if (kind !== 'bool')
|
||||
throw new Error('Condition must be bool');
|
||||
|
||||
if (value) {
|
||||
return evaluate(ast.then, env);
|
||||
} else {
|
||||
return evaluate(ast.else, env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateBinaryOp(op: string, left: Value, right: Value): Value {
|
||||
const { value: leftValue, kind: leftKind } = left;
|
||||
const { value: rightValue, kind: rightKind } = right;
|
||||
|
||||
const bothNumbers = ((leftKind === 'int' || leftKind === 'float')) && ((rightKind === 'int' || rightKind === 'float'));
|
||||
if (!bothNumbers)
|
||||
throw new Error(`Not numbers: ${left}, ${right}`);
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
return { value: leftValue + rightValue, kind: 'int' };
|
||||
|
||||
case '-':
|
||||
return { value: leftValue - rightValue, kind: 'int' };
|
||||
|
||||
case '*':
|
||||
return { value: leftValue * rightValue, kind: 'int' }
|
||||
|
||||
case '/':
|
||||
return { value: leftValue / rightValue, kind: 'int' }
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown operation: ${op}`);
|
||||
}
|
||||
}
|
||||
30
src/main.ts
Normal file
30
src/main.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { evaluate } from './interpreter'
|
||||
import type { AST } from './ast'
|
||||
import type { Env } from './env'
|
||||
|
||||
const ast: AST = {
|
||||
kind: 'binaryop',
|
||||
operator: '+',
|
||||
left: {
|
||||
kind: 'literal',
|
||||
value: { kind: 'int', value: 1 }
|
||||
},
|
||||
right: {
|
||||
kind: 'binaryop',
|
||||
operator: '*',
|
||||
left: {
|
||||
kind: 'literal',
|
||||
value: { kind: 'int', value: 2 }
|
||||
},
|
||||
right: {
|
||||
kind: 'literal',
|
||||
value: { kind: 'int', value: 3 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const env: Env = new Map();
|
||||
|
||||
const res = evaluate(ast, env);
|
||||
|
||||
console.log(res);
|
||||
21
src/types.ts
Normal file
21
src/types.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export type IntValue = {
|
||||
kind: 'int'
|
||||
value: number
|
||||
}
|
||||
|
||||
export type FloatValue = {
|
||||
kind: 'float'
|
||||
value: number
|
||||
}
|
||||
|
||||
export type StringValue = {
|
||||
kind: 'string'
|
||||
value: string
|
||||
}
|
||||
|
||||
export type BoolValue = {
|
||||
kind: 'bool'
|
||||
value: boolean
|
||||
}
|
||||
|
||||
export type Value = IntValue | FloatValue | StringValue | BoolValue;
|
||||
Loading…
Add table
Add a link
Reference in a new issue