Compare commits

..

No commits in common. "record" and "main" have entirely different histories.
record ... main

10 changed files with 5295 additions and 5841 deletions

BIN
bun.lockb

Binary file not shown.

View File

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

View File

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

View File

@ -2,17 +2,13 @@ import {
type ContinuationExpression,
type PrimitiveOperationExpression,
type ApplicationExpression,
type RecordExpression,
type Program,
type Value,
type RecordExpressionTuple,
type SelectExpression,
} from '@/parser';
import { Environment, type Denotable, type DenotableRecord } from '.';
import { Environment, type Denotable } from '.';
import {
BadArgumentError,
InvalidStateError,
InvalidType,
NotImplementedError,
type TracingLogger,
} from '@/utils';
@ -33,11 +29,6 @@ const evaluateValue = (
if ('int' in value) {
return { type: 'int', value: value.int };
}
if ('bool' in value) {
return { type: 'bool', value: value.bool };
}
if ('name' in value) {
return env.get(value.name);
}
@ -116,89 +107,6 @@ 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 = (
expr: ContinuationExpression,
env: Environment,
@ -223,20 +131,10 @@ const evaluteContinuationExpression = (
}
if ('record' in expr) {
logger.debug('Evaluating record');
return evaluateRecordExpression(
expr,
env,
logger.createChild('evaluateRecordExpression'),
);
throw new NotImplementedError('Continuation records are not supported yet');
}
if ('select' in expr) {
logger.debug('Evaluating select');
return evaluateSelectExpression(
expr,
env,
logger.createChild('evaluateSelectExpression'),
);
throw new NotImplementedError('Continuation select is not supported yet');
}
if ('offset' in expr) {
throw new NotImplementedError('Continuation offset is not supported yet');

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -45,10 +45,3 @@ test('Application of identity function', async () => {
const result = await evaluate(ast, testingLogger);
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,7 +19,4 @@ export namespace TestPrograms {
export const Application = Bun.file(
join(import.meta.dir, 'application.cps'),
).text();
export const RecordConstruction = Bun.file(
join(import.meta.dir, 'record.cps'),
).text();
}

View File

@ -1,7 +0,0 @@
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], [])
)
)
)