Compare commits
No commits in common. "89db6cf917002aab329ad35b89444fe1eab1d1f8" and "9d1bd0d489870a1d9a3c971542a248def9d84b0d" have entirely different histories.
89db6cf917
...
9d1bd0d489
@ -10,13 +10,9 @@
|
|||||||
},
|
},
|
||||||
"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'"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
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>
|
||||||
@ -22,14 +23,9 @@ 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
|
||||||
@ -37,7 +33,6 @@ export type DenotableValue =
|
|||||||
| string
|
| string
|
||||||
| Uint8Array
|
| Uint8Array
|
||||||
| DenotableFunction
|
| DenotableFunction
|
||||||
| DenotableRecord
|
|
||||||
| Identifier;
|
| Identifier;
|
||||||
|
|
||||||
export type Denotable = {
|
export type Denotable = {
|
||||||
|
@ -2,17 +2,13 @@ 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, type DenotableRecord } from '.';
|
import { Environment, type Denotable } from '.';
|
||||||
import {
|
import {
|
||||||
BadArgumentError,
|
BadArgumentError,
|
||||||
InvalidStateError,
|
InvalidStateError,
|
||||||
InvalidType,
|
|
||||||
NotImplementedError,
|
NotImplementedError,
|
||||||
type TracingLogger,
|
type TracingLogger,
|
||||||
} from '@/utils';
|
} from '@/utils';
|
||||||
@ -33,11 +29,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -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 = (
|
const evaluteContinuationExpression = (
|
||||||
expr: ContinuationExpression,
|
expr: ContinuationExpression,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -223,20 +131,10 @@ const evaluteContinuationExpression = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ('record' in expr) {
|
if ('record' in expr) {
|
||||||
logger.debug('Evaluating record');
|
throw new NotImplementedError('Continuation records are not supported yet');
|
||||||
return evaluateRecordExpression(
|
|
||||||
expr,
|
|
||||||
env,
|
|
||||||
logger.createChild('evaluateRecordExpression'),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ('select' in expr) {
|
if ('select' in expr) {
|
||||||
logger.debug('Evaluating select');
|
throw new NotImplementedError('Continuation select is not supported yet');
|
||||||
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');
|
||||||
|
@ -17,11 +17,11 @@ SelectExpression
|
|||||||
_?
|
_?
|
||||||
LPAREN
|
LPAREN
|
||||||
_?
|
_?
|
||||||
index:Integer
|
record:Integer
|
||||||
_?
|
_?
|
||||||
COMMA
|
COMMA
|
||||||
_?
|
_?
|
||||||
record:VarStatement
|
val:Value
|
||||||
_?
|
_?
|
||||||
COMMA
|
COMMA
|
||||||
_?
|
_?
|
||||||
@ -31,7 +31,7 @@ SelectExpression
|
|||||||
_?
|
_?
|
||||||
continuation:ContinuationExpression
|
continuation:ContinuationExpression
|
||||||
_?
|
_?
|
||||||
RPAREN { return { select: { index, record, bind, continuation } }; }
|
RPAREN { return { select: { record, val, bind, continuation } }; }
|
||||||
|
|
||||||
OffsetExpression
|
OffsetExpression
|
||||||
= OFFSET
|
= OFFSET
|
||||||
@ -86,17 +86,9 @@ SwitchExpression
|
|||||||
RPAREN { return { switch: { switchIndex, continuations } }; }
|
RPAREN { return { switch: { switchIndex, continuations } }; }
|
||||||
|
|
||||||
ApplicationExpression
|
ApplicationExpression
|
||||||
= APP
|
= APP _? LPAREN _? fn:(LabelStatement / VarStatement) _? COMMA _? args:ValueList _? RPAREN {
|
||||||
_?
|
return { application: { fn, args } };
|
||||||
LPAREN
|
}
|
||||||
_?
|
|
||||||
fn:(LabelStatement / VarStatement)
|
|
||||||
_?
|
|
||||||
COMMA
|
|
||||||
_?
|
|
||||||
args:ValueList
|
|
||||||
_?
|
|
||||||
RPAREN { return { application: { fn, args } }; }
|
|
||||||
|
|
||||||
FixBinding
|
FixBinding
|
||||||
= LPAREN
|
= LPAREN
|
||||||
@ -177,29 +169,16 @@ PrimitiveOperationExpression
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessPath
|
RecordExpressionTuple
|
||||||
= OffsetPath
|
= LPAREN
|
||||||
/ SelectPath
|
|
||||||
|
|
||||||
OffsetPath = OFFP _ offset:Integer { return { offset: offset.int }; }
|
|
||||||
|
|
||||||
SelectPath
|
|
||||||
= SELP
|
|
||||||
_?
|
_?
|
||||||
LPAREN
|
variable:VarStatement
|
||||||
_?
|
|
||||||
index:Integer
|
|
||||||
_?
|
_?
|
||||||
COMMA
|
COMMA
|
||||||
_?
|
_?
|
||||||
accessPath:AccessPath
|
offset:OffsetStatement
|
||||||
_?
|
_?
|
||||||
RPAREN { return { select: { index, accessPath } }; }
|
RPAREN { return { variable, offset }; }
|
||||||
|
|
||||||
RecordExpressionTuple
|
|
||||||
= LPAREN _? value:Value _? COMMA _? accessPath:AccessPath _? RPAREN {
|
|
||||||
return { value, accessPath };
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordExpressionTupleList
|
RecordExpressionTupleList
|
||||||
= LBRACKET
|
= LBRACKET
|
||||||
@ -223,7 +202,7 @@ RecordExpression
|
|||||||
_?
|
_?
|
||||||
COMMA
|
COMMA
|
||||||
_?
|
_?
|
||||||
address:Identifier
|
address:Literal
|
||||||
_?
|
_?
|
||||||
COMMA
|
COMMA
|
||||||
_?
|
_?
|
||||||
@ -255,10 +234,18 @@ IntStatement = INT _ int:Integer { return int; }
|
|||||||
|
|
||||||
RealStatement = REAL _ real:Real { return real; }
|
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; }
|
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('') };
|
||||||
@ -304,8 +291,7 @@ ComparisonOperation
|
|||||||
/ "||"
|
/ "||"
|
||||||
/ "&&"
|
/ "&&"
|
||||||
|
|
||||||
Integer
|
Integer = digits:("-"? [0-9]+) !"." { return { int: parseInt(digits.join(''), 10) }; }
|
||||||
= digits:("-"? [0-9]+) !"." { return { int: parseInt(digits.join(''), 10) }; }
|
|
||||||
|
|
||||||
QuotedString
|
QuotedString
|
||||||
= "'" content:[^']* "'" { return content.join(''); }
|
= "'" content:[^']* "'" { return content.join(''); }
|
||||||
@ -313,11 +299,9 @@ QuotedString
|
|||||||
|
|
||||||
Real
|
Real
|
||||||
= value:("-"? [0-9]+ ("." [0-9]+)?) {
|
= value:("-"? [0-9]+ ("." [0-9]+)?) {
|
||||||
return {
|
return { real: parseFloat(
|
||||||
real: parseFloat(
|
value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''),
|
||||||
value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''),
|
) };
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal
|
Literal
|
||||||
|
@ -2,6 +2,5 @@ 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.ContinuationExpression[] => {
|
export const peggyParse = (source: string): peggy.FunctionDefinition[] =>
|
||||||
return peggy.parse(source);
|
peggy.parse(source);
|
||||||
};
|
|
||||||
|
10923
src/parser/parser.ts
10923
src/parser/parser.ts
File diff suppressed because it is too large
Load Diff
@ -45,10 +45,3 @@ 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 });
|
|
||||||
});
|
|
||||||
|
@ -19,7 +19,4 @@ 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();
|
|
||||||
}
|
}
|
||||||
|
@ -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], [])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
Loading…
Reference in New Issue
Block a user