Compare commits

...

3 Commits

Author SHA1 Message Date
Lizzy Hunt
89db6cf917
add naive record construction support 2024-03-05 15:36:31 -07:00
Lizzy Hunt
5e9a34e642
fix parsing of RecordExpressions 2024-03-05 14:56:17 -07:00
Lizzy Hunt
2f77b3fb5a
evaluate booleans 2024-03-05 14:28:28 -07:00
10 changed files with 5683 additions and 5137 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -10,9 +10,13 @@
}, },
"dependencies": { "dependencies": {
"minimist": "^1.2.8", "minimist": "^1.2.8",
"nodemon": "^3.1.0",
"peggy": "^4.0.0", "peggy": "^4.0.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",
"prettier-plugin-pegjs": "^2.0.2", "prettier-plugin-pegjs": "^2.0.2",
"ts-pegjs": "^4.2.1" "ts-pegjs": "^4.2.1"
},
"scripts": {
"watch-test": "nodemon -e ts,cps --exec 'bun test'"
} }
} }

View File

@ -1,5 +1,4 @@
import type { Identifier } from '@/parser'; import type { Identifier } from '@/parser';
import { testingLogger } from '@t/logger';
export type UnionDenotableType = export type UnionDenotableType =
| Array<DenotableType | DenotableFunctionSignature> | Array<DenotableType | DenotableFunctionSignature>
@ -23,9 +22,14 @@ export type DenotableType =
| 'real' | 'real'
| 'bool' | 'bool'
| 'string' | 'string'
| 'record'
| 'bytearray' | 'bytearray'
| 'function' | 'function';
| 'reference';
export type DenotableRecord = {
length: number;
record: Array<Denotable>;
};
export type DenotableValue = export type DenotableValue =
| null | null
@ -33,6 +37,7 @@ export type DenotableValue =
| string | string
| Uint8Array | Uint8Array
| DenotableFunction | DenotableFunction
| DenotableRecord
| Identifier; | Identifier;
export type Denotable = { export type Denotable = {

View File

@ -2,13 +2,17 @@ import {
type ContinuationExpression, type ContinuationExpression,
type PrimitiveOperationExpression, type PrimitiveOperationExpression,
type ApplicationExpression, type ApplicationExpression,
type RecordExpression,
type Program, type Program,
type Value, type Value,
type RecordExpressionTuple,
type SelectExpression,
} from '@/parser'; } from '@/parser';
import { Environment, type Denotable } from '.'; import { Environment, type Denotable, type DenotableRecord } from '.';
import { import {
BadArgumentError, BadArgumentError,
InvalidStateError, InvalidStateError,
InvalidType,
NotImplementedError, NotImplementedError,
type TracingLogger, type TracingLogger,
} from '@/utils'; } from '@/utils';
@ -29,6 +33,11 @@ const evaluateValue = (
if ('int' in value) { if ('int' in value) {
return { type: 'int', value: value.int }; return { type: 'int', value: value.int };
} }
if ('bool' in value) {
return { type: 'bool', value: value.bool };
}
if ('name' in value) { if ('name' in value) {
return env.get(value.name); return env.get(value.name);
} }
@ -107,6 +116,89 @@ const evaluatePrimitiveOperation = (
); );
}; };
export const evaluateRecordTuple = (
tuple: RecordExpressionTuple,
env: Environment,
logger: TracingLogger,
): Denotable => {
const { value, accessPath } = tuple;
const record = evaluateValue(value, env, logger.createChild('evaluateValue'));
if (record.type === 'record') {
// TODO: Implement nested records at accessPath
logger.debug(JSON.stringify(accessPath, null, 2));
throw new NotImplementedError('Nested records are not yet supported');
}
return record;
};
export const evaluateRecordExpression = (
{ record }: RecordExpression,
env: Environment,
logger: TracingLogger,
): Denotable => {
const {
records,
address: { name: address },
body,
} = record;
const childEnv = env.createChild();
const recordTuple = records.map(record =>
evaluateRecordTuple(
record,
childEnv,
logger.createChild('evaluateRecordTuple'),
),
);
const length = recordTuple.length;
childEnv.set(address, {
type: 'record',
value: { length, record: recordTuple },
});
return evaluteContinuationExpression(
body,
childEnv,
logger.createChild('evaluteContinuationExpression'),
);
};
export const evaluateSelectExpression = (
{ select }: SelectExpression,
env: Environment,
logger: TracingLogger,
): Denotable => {
const {
index: { int: index },
record,
bind,
continuation,
} = select;
const childEnv = env.createChild();
const recordValue = evaluateValue(
record,
env,
logger.createChild('evaluateValue'),
);
if (recordValue.type !== 'record') {
throw new InvalidType('Expected record type');
}
const { value } = recordValue as { value: DenotableRecord };
const selected = value.record[index];
childEnv.set(bind.name, selected);
return evaluteContinuationExpression(
continuation,
childEnv,
logger.createChild('evaluteContinuationExpression'),
);
};
const evaluteContinuationExpression = ( const evaluteContinuationExpression = (
expr: ContinuationExpression, expr: ContinuationExpression,
env: Environment, env: Environment,
@ -131,10 +223,20 @@ const evaluteContinuationExpression = (
} }
if ('record' in expr) { if ('record' in expr) {
throw new NotImplementedError('Continuation records are not supported yet'); logger.debug('Evaluating record');
return evaluateRecordExpression(
expr,
env,
logger.createChild('evaluateRecordExpression'),
);
} }
if ('select' in expr) { if ('select' in expr) {
throw new NotImplementedError('Continuation select is not supported yet'); logger.debug('Evaluating select');
return evaluateSelectExpression(
expr,
env,
logger.createChild('evaluateSelectExpression'),
);
} }
if ('offset' in expr) { if ('offset' in expr) {
throw new NotImplementedError('Continuation offset is not supported yet'); throw new NotImplementedError('Continuation offset is not supported yet');

View File

@ -17,11 +17,11 @@ SelectExpression
_? _?
LPAREN LPAREN
_? _?
record:Integer index:Integer
_? _?
COMMA COMMA
_? _?
val:Value record:VarStatement
_? _?
COMMA COMMA
_? _?
@ -31,7 +31,7 @@ SelectExpression
_? _?
continuation:ContinuationExpression continuation:ContinuationExpression
_? _?
RPAREN { return { select: { record, val, bind, continuation } }; } RPAREN { return { select: { index, record, bind, continuation } }; }
OffsetExpression OffsetExpression
= OFFSET = OFFSET
@ -86,9 +86,17 @@ SwitchExpression
RPAREN { return { switch: { switchIndex, continuations } }; } RPAREN { return { switch: { switchIndex, continuations } }; }
ApplicationExpression ApplicationExpression
= APP _? LPAREN _? fn:(LabelStatement / VarStatement) _? COMMA _? args:ValueList _? RPAREN { = APP
return { application: { fn, args } }; _?
} LPAREN
_?
fn:(LabelStatement / VarStatement)
_?
COMMA
_?
args:ValueList
_?
RPAREN { return { application: { fn, args } }; }
FixBinding FixBinding
= LPAREN = LPAREN
@ -169,16 +177,29 @@ PrimitiveOperationExpression
}; };
} }
RecordExpressionTuple AccessPath
= LPAREN = OffsetPath
/ SelectPath
OffsetPath = OFFP _ offset:Integer { return { offset: offset.int }; }
SelectPath
= SELP
_? _?
variable:VarStatement LPAREN
_?
index:Integer
_? _?
COMMA COMMA
_? _?
offset:OffsetStatement accessPath:AccessPath
_? _?
RPAREN { return { variable, offset }; } RPAREN { return { select: { index, accessPath } }; }
RecordExpressionTuple
= LPAREN _? value:Value _? COMMA _? accessPath:AccessPath _? RPAREN {
return { value, accessPath };
}
RecordExpressionTupleList RecordExpressionTupleList
= LBRACKET = LBRACKET
@ -202,7 +223,7 @@ RecordExpression
_? _?
COMMA COMMA
_? _?
address:Literal address:Identifier
_? _?
COMMA COMMA
_? _?
@ -234,18 +255,10 @@ IntStatement = INT _ int:Integer { return int; }
RealStatement = REAL _ real:Real { return real; } RealStatement = REAL _ real:Real { return real; }
BoolStatement = BOOL _ bool:Integer { return bool; } BoolStatement = BOOL _ bool:Integer { return { bool: bool.int }; }
StringStatement = STRING _ string:QuotedString { return string; } StringStatement = STRING _ string:QuotedString { return string; }
AccessStatement
= OffsetStatement
/ SelectStatement
OffsetStatement = OFFP _ offset:Integer { return offset; }
SelectStatement = SELP _ offset:Integer { return offset; }
Identifier Identifier
= name:([A-Za-z] (LETTER / DIGIT / SAFE_SYMBOL)*) { = name:([A-Za-z] (LETTER / DIGIT / SAFE_SYMBOL)*) {
return { name: name[0] + name[1].join('') }; return { name: name[0] + name[1].join('') };
@ -291,7 +304,8 @@ ComparisonOperation
/ "||" / "||"
/ "&&" / "&&"
Integer = digits:("-"? [0-9]+) !"." { return { int: parseInt(digits.join(''), 10) }; } Integer
= digits:("-"? [0-9]+) !"." { return { int: parseInt(digits.join(''), 10) }; }
QuotedString QuotedString
= "'" content:[^']* "'" { return content.join(''); } = "'" content:[^']* "'" { return content.join(''); }
@ -299,9 +313,11 @@ QuotedString
Real Real
= value:("-"? [0-9]+ ("." [0-9]+)?) { = value:("-"? [0-9]+ ("." [0-9]+)?) {
return { real: parseFloat( return {
value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''), real: parseFloat(
) }; value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''),
),
};
} }
Literal Literal

View File

@ -2,5 +2,6 @@ export * from './generate';
export * from './parser'; export * from './parser';
import * as peggy from './parser'; import * as peggy from './parser';
export const peggyParse = (source: string): peggy.FunctionDefinition[] => export const peggyParse = (source: string): peggy.ContinuationExpression[] => {
peggy.parse(source); return peggy.parse(source);
};

File diff suppressed because it is too large Load Diff

View File

@ -45,3 +45,10 @@ test('Application of identity function', async () => {
const result = await evaluate(ast, testingLogger); const result = await evaluate(ast, testingLogger);
expect(result).toEqual({ type: 'int', value: 3 }); expect(result).toEqual({ type: 'int', value: 3 });
}); });
test('Record construction', async () => {
const ast = peggyParse(await TestPrograms.RecordConstruction);
const result = await evaluate(ast, testingLogger);
expect(result).toEqual({ type: 'int', value: 3 });
});

View File

@ -19,4 +19,7 @@ export namespace TestPrograms {
export const Application = Bun.file( export const Application = Bun.file(
join(import.meta.dir, 'application.cps'), join(import.meta.dir, 'application.cps'),
).text(); ).text();
export const RecordConstruction = Bun.file(
join(import.meta.dir, 'record.cps'),
).text();
} }

7
test/programs/record.cps Normal file
View File

@ -0,0 +1,7 @@
RECORD([(INT 1, OFFp 0), (INT 2, OFFp 0)], record,
SELECT(0, VAR record, one,
SELECT(1, VAR record, two,
PRIMOP(+, [VAR one, VAR two], [result], [])
)
)
)