First commit for CG

This commit is contained in:
Dustin Swan 2026-01-29 22:39:33 -07:00
commit d60e5aa29f
No known key found for this signature in database
GPG key ID: 30D46587E2100467
11 changed files with 1397 additions and 0 deletions

34
src/ast.ts Normal file
View 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
View file

@ -0,0 +1,3 @@
import type { Value } from './types';
export type Env = Map<string, Value>

64
src/interpreter.ts Normal file
View 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
View 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
View 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;