Skip to content

Commit

Permalink
feat: enhanced the syntax, simplified the grammar
Browse files Browse the repository at this point in the history
  • Loading branch information
novusnota committed Nov 22, 2024
1 parent f1562ff commit 40f118b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 110 deletions.
30 changes: 6 additions & 24 deletions src/grammar/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,7 @@ export type AstAsmShuffle = {
};

// NOTE: should it be added to AstNode?
export type AstAsmExpression =
| AstAsmExpressionDef
| AstAsmExpressionList
| AstAsmPrimitive;

/** `{ AstAsmExpression* } : AstAsmInstruction` */
export type AstAsmExpressionDef = {
kind: "asm_expr_def";
expressions: AstAsmExpression[];
name: AstAsmInstruction;
loc: SrcInfo;
};

/** `{ AstAsmExpression* }` */
export type AstAsmExpressionList = {
kind: "asm_expr_list";
expressions: AstAsmExpression[];
loc: SrcInfo;
};
export type AstAsmExpression = AstAsmPrimitive;

export type AstAsmPrimitive =
| AstAsmString
Expand Down Expand Up @@ -138,16 +120,16 @@ export type AstAsmControlReg = {
};

/**
* `s0`, `s1`, ..., `s15`
* or `i s()`,
* where i ∈ [0, 255]
* `s0`, `s1`, ..., `s255`
*/
export type AstAsmStackReg = {
kind: "asm_stack_reg";
value: bigint;
/**
* Is it either of `s0`, `s1`, ..., `s15`?
* If not, then it's `i s()`, where i ∈ [0, 255]
* Whether there's a single literal for expressing this stack register in FunC/Fift?
*
* Single literals are written like `s0`, `s1`, ..., `s15`,
* while other stack registers are expressed as `i s()`, where i ∈ [0, 255]
*/
isLiteral: boolean;
loc: SrcInfo;
Expand Down
46 changes: 28 additions & 18 deletions src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -99,30 +99,40 @@ Tact {
| external "(" Parameter? ")" "{" Statement* "}" --externalRegular
| external "(" stringLiteral ")" "{" Statement* "}" --externalComment

// FIXME: prettyPrinter.ts → writeFunction.ts, hash.ts, compare.ts
AsmExpression = "{" AsmExpression* "}" ":" asmInstruction --definition
| "{" AsmExpression* "}" --list
// FIXME: prettyPrinter.ts + writeFunction.ts, hash.ts, compare.ts
AsmExpression = "{" (~"}" any)* "}" --listWithHelpfulErrorMessage // used only for error messages
| asmPrimitive

// Various instructions not forming a block
asmPrimitive = "\"" (~"\"" any)* "\"" --string
| "x{" hexDigit* "_"? "}" --hex
| "b{" binDigit* "}" --bin
| "c" digit digit? --controlRegister
| "s" digit digit? --stackRegister
| digit digit? digit? whiteSpace+ "s()" --stackRegister255
| "-"? digit+ --number
| asmInstruction --custom
// Various primitives and instructions not forming a block
asmPrimitive = asmString
| asmHex
| asmBin
| asmControlReg
| asmStackReg
| asmStackReg256
| asmNumber
| asmInstruction

// It's here mostly to provide better error messages
// for people coming from FunC/Fift background
asmString (string) = "\"" (~"\"" any)* "\""
asmHex (hex bitstring) = "x{" hexDigit* "_"? "}"
asmBin (binary bitstring) = "b{" binDigit* "}"
asmControlReg (control register) = "c" digit digit?
asmStackReg (stack register) = "s" digit digit? digit?
// It's here mostly to provide better error messages
// for people coming from FunC/Fift background,
// gently guiding them towards simpler s0...s255 syntax
asmStackReg256 (indexed stack register) = digit digit? digit? whiteSpace+ "s()"
asmNumber (number) = "-"? digit+

// To ensure correct parse,
// 1. instructions cannot contain braces
// 2. and cannot be braces themselves
asmInstruction = ~(("{" | "}") ~asmWord) asmWord

// Additionally, the minimal word length is 2 characters,
// not including the optional minus at the start
asmWord = "-"? asmWordPart asmWordPart+
asmWordPart = (letterAscii | digit | "_" | "#" | ":")
asmInstruction (an instruction) = ~(("{" | "}") ~asmWord) asmWord
asmWord = "-"? asmWordPart+
// NOTE: We can limit this further to letterAsciiUC, then add optional "l"? by the end.
asmWordPart = letterAscii | digit | "_" | "#" | ":"

Statement = StatementLet
| StatementBlock
Expand Down
96 changes: 29 additions & 67 deletions src/grammar/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,37 +515,32 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
AsmExpression(expression) {
return expression.astOfAsmExpression();
},
AsmExpression_definition(_lbrace, expressions, _rbrace, _colon, name) {
return {
kind: "asm_expr_def",
expressions: expressions.children.map((e) =>
e.astOfAsmExpression(),
),
name: name.astOfAsmExpression(),
loc: createRef(this),
};
},
AsmExpression_list(_lbrace, expressions, _rbrace) {
return {
kind: "asm_expr_list",
expressions: expressions.children.map((e) =>
e.astOfAsmExpression(),
),
loc: createRef(this),
};
AsmExpression_listWithHelpfulErrorMessage(_lbrace, _any, _rbrace) {
throwSyntaxError(
'The Fift\'s word list syntax "{ ... }" is not supported',
createRef(this),
);
},
asmPrimitive(primitive) {
return primitive.astOfAsmExpression();
},
asmPrimitive_string(_startQuotationMark, string, _endQuotationMark) {
// TODO(grammar.ts): perform checks for inner contents of the string
asmString(_startQuotationMark, string, _endQuotationMark) {
// A best-effor check to inform the user of errors in translation
// of TVM instructions between FunC (or other languages) and Tact
const src = string.sourceString;
if (src.match(/^-?[A-Z0-9_#:]+l?$/) !== null) {
throwSyntaxError(
`The instruction "${src}" doesn't exist, did you mean ${src}?`,
createRef(this),
);
}
return {
kind: "asm_string",
value: string.sourceString,
loc: createRef(this),
};
},
asmPrimitive_hex(_prefix, digits, optUnderscore, _rbrace) {
asmHex(_prefix, digits, optUnderscore, _rbrace) {
const length = digits.numChildren;
const underscore = unwrapOptNode(optUnderscore, (t) => t.sourceString);
if (length > 128) {
Expand All @@ -561,7 +556,7 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
loc: createRef(this),
};
},
asmPrimitive_bin(_prefix, digits, _rbrace) {
asmBin(_prefix, digits, _rbrace) {
const length = digits.numChildren;
if (length > 128) {
throwSyntaxError(
Expand All @@ -575,7 +570,7 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
loc: createRef(this),
};
},
asmPrimitive_controlRegister(_prefix, digit, optDigit) {
asmControlReg(_prefix, digit, optDigit) {
const secondDigit = unwrapOptNode(optDigit, (t) => t);
let number = bigintOfIntLiteral(digit);
if (secondDigit !== null) {
Expand All @@ -593,32 +588,7 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
loc: createRef(this),
};
},
asmPrimitive_stackRegister(_prefix, digit, optDigit) {
const secondDigit = unwrapOptNode(optDigit, (t) => t);
let number = bigintOfIntLiteral(digit);
if (secondDigit !== null) {
number = number * 10n + bigintOfIntLiteral(secondDigit);
}
if (number > 15) {
throwSyntaxError(
`The stack register literal s${number.toString(10)} doesn't exist. Perhaps you meant to write "${number.toString(10)} s()" instead?`,
createRef(this),
);
}
return {
kind: "asm_stack_reg",
isLiteral: true,
value: number,
loc: createRef(this),
};
},
asmPrimitive_stackRegister255(
digit,
optSecondDigit,
optThirdDigit,
_ws,
_sParentheses,
) {
asmStackReg(_prefix, digit, optSecondDigit, optThirdDigit) {
const secondDigit = unwrapOptNode(optSecondDigit, (t) => t);
const thirdDigit = unwrapOptNode(optThirdDigit, (t) => t);
let number = bigintOfIntLiteral(digit);
Expand All @@ -635,23 +605,26 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
} else if (secondDigit !== null) {
number = number * 10n + bigintOfIntLiteral(secondDigit);
}
if (number > 255) {
if (number > 255n || number < 0n) {
throwSyntaxError(
`The stack register ${number.toString(10)} s() doesn't exist`,
`The stack register s${number.toString(10)} doesn't exist`,
createRef(this),
);
}
return {
kind: "asm_stack_reg",
isLiteral: false,
isLiteral: number < 16n ? true : false,
value: number,
loc: createRef(this),
};
},
// TODO: write the last things here, then fix the asm generation
// TODO: then, fix the prettyPrinter -- leave stuff as is, don't print
// TODO: hash.ts and compare.ts too, somehow...
asmPrimitive_number(optNeg, digits) {
asmStackReg256(digit, optSecondDigit, optThirdDigit, _ws, _literal) {
throwSyntaxError(
`The "i s()" syntax is deprecated in favor of using one of the "s0", "s1", ..., "s255" stack registers`,
createRef(this),
);
},
asmNumber(optNeg, digits) {
const negate = unwrapOptNode(optNeg, (t) => t);
let number = bigintOfIntLiteral(digits);
if (negate !== null) {
Expand All @@ -663,17 +636,6 @@ semantics.addOperation<AstAsmExpression>("astOfAsmExpression", {
loc: createRef(this),
};
},
// function astOfNumber(node: Node): AstNode {
// return createAstNode({
// kind: "number",
// base: baseOfIntLiteral(node),
// value: bigintOfIntLiteral(node),
// loc: createRef(node),
// });
// }
asmPrimitive_custom(instruction) {
return instruction.astOfAsmExpression();
},
});

semantics.addOperation<AstFunctionAttribute>("astOfFunctionAttributes", {
Expand Down
2 changes: 1 addition & 1 deletion src/types/resolveExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ function resolveStaticCall(
) !== undefined
) {
throwCompilationError(
`Static function ${idTextErr(exp.function)} does not exist. Perhaps you meant to call ".${idText(exp.function)}(...)" extension function?`,
`Static function ${idTextErr(exp.function)} does not exist. Perhaps you meant to call ".${idText(exp.function)}(...)" or "self.${idText(exp.function)}(...)"?`,
exp.loc,
);
}
Expand Down

0 comments on commit 40f118b

Please sign in to comment.