add naive record construction support
This commit is contained in:
parent
5e9a34e642
commit
89db6cf917
@ -22,9 +22,14 @@ export type DenotableType =
|
||||
| 'real'
|
||||
| 'bool'
|
||||
| 'string'
|
||||
| 'record'
|
||||
| 'bytearray'
|
||||
| 'function'
|
||||
| 'reference';
|
||||
| 'function';
|
||||
|
||||
export type DenotableRecord = {
|
||||
length: number;
|
||||
record: Array<Denotable>;
|
||||
};
|
||||
|
||||
export type DenotableValue =
|
||||
| null
|
||||
@ -32,6 +37,7 @@ export type DenotableValue =
|
||||
| string
|
||||
| Uint8Array
|
||||
| DenotableFunction
|
||||
| DenotableRecord
|
||||
| Identifier;
|
||||
|
||||
export type Denotable = {
|
||||
|
@ -2,13 +2,17 @@ import {
|
||||
type ContinuationExpression,
|
||||
type PrimitiveOperationExpression,
|
||||
type ApplicationExpression,
|
||||
type RecordExpression,
|
||||
type Program,
|
||||
type Value,
|
||||
type RecordExpressionTuple,
|
||||
type SelectExpression,
|
||||
} from '@/parser';
|
||||
import { Environment, type Denotable } from '.';
|
||||
import { Environment, type Denotable, type DenotableRecord } from '.';
|
||||
import {
|
||||
BadArgumentError,
|
||||
InvalidStateError,
|
||||
InvalidType,
|
||||
NotImplementedError,
|
||||
type TracingLogger,
|
||||
} from '@/utils';
|
||||
@ -112,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 = (
|
||||
expr: ContinuationExpression,
|
||||
env: Environment,
|
||||
@ -136,10 +223,20 @@ const evaluteContinuationExpression = (
|
||||
}
|
||||
|
||||
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) {
|
||||
throw new NotImplementedError('Continuation select is not supported yet');
|
||||
logger.debug('Evaluating select');
|
||||
return evaluateSelectExpression(
|
||||
expr,
|
||||
env,
|
||||
logger.createChild('evaluateSelectExpression'),
|
||||
);
|
||||
}
|
||||
if ('offset' in expr) {
|
||||
throw new NotImplementedError('Continuation offset is not supported yet');
|
||||
|
@ -17,11 +17,11 @@ SelectExpression
|
||||
_?
|
||||
LPAREN
|
||||
_?
|
||||
record:Integer
|
||||
index:Integer
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
val:Value
|
||||
record:VarStatement
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
@ -31,7 +31,7 @@ SelectExpression
|
||||
_?
|
||||
continuation:ContinuationExpression
|
||||
_?
|
||||
RPAREN { return { select: { record, val, bind, continuation } }; }
|
||||
RPAREN { return { select: { index, record, bind, continuation } }; }
|
||||
|
||||
OffsetExpression
|
||||
= OFFSET
|
||||
@ -86,9 +86,17 @@ 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
|
||||
@ -169,16 +177,29 @@ PrimitiveOperationExpression
|
||||
};
|
||||
}
|
||||
|
||||
RecordExpressionTuple
|
||||
= LPAREN
|
||||
AccessPath
|
||||
= OffsetPath
|
||||
/ SelectPath
|
||||
|
||||
OffsetPath = OFFP _ offset:Integer { return { offset: offset.int }; }
|
||||
|
||||
SelectPath
|
||||
= SELP
|
||||
_?
|
||||
value:Value
|
||||
LPAREN
|
||||
_?
|
||||
index:Integer
|
||||
_?
|
||||
COMMA
|
||||
_?
|
||||
offset:OffsetStatement
|
||||
accessPath:AccessPath
|
||||
_?
|
||||
RPAREN { return { value, offset }; }
|
||||
RPAREN { return { select: { index, accessPath } }; }
|
||||
|
||||
RecordExpressionTuple
|
||||
= LPAREN _? value:Value _? COMMA _? accessPath:AccessPath _? RPAREN {
|
||||
return { value, accessPath };
|
||||
}
|
||||
|
||||
RecordExpressionTupleList
|
||||
= LBRACKET
|
||||
@ -238,14 +259,6 @@ BoolStatement = BOOL _ bool:Integer { return { bool: bool.int }; }
|
||||
|
||||
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('') };
|
||||
@ -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
|
||||
= "'" content:[^']* "'" { return content.join(''); }
|
||||
@ -299,9 +313,11 @@ QuotedString
|
||||
|
||||
Real
|
||||
= value:("-"? [0-9]+ ("." [0-9]+)?) {
|
||||
return { real: parseFloat(
|
||||
return {
|
||||
real: parseFloat(
|
||||
value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''),
|
||||
) };
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Literal
|
||||
|
6166
src/parser/parser.ts
6166
src/parser/parser.ts
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
RECORD([(INT 1, OFFp 0), (INT 2, OFFp 0)], record,
|
||||
SELECT(0, VAR one, record,
|
||||
SELECT(1, VAR two, 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