This patch fixes the Lua arithmetic model at parser level only. Runtime level fixtures are left for future work. MOTIVATION Space Lua treats all numbers as IEEE-754 doubles (JS semantics), so it preserves negative zero. Lua uses integers and floats. The literal "-0" in Lua is parsed as unary minus applied to the integer literal "0", which yields the integer "0" (no sign). This difference flips the sign of the divisor in "1/-0" and "-1/-0". Although it could be fixed without touching the parser by changing only unary minus evaluation, this commit goes a little further and provides integer vs float differenciating at the parser level as well uses it to fix the unary minus evaluation. Extensive tests are added to test this exact change works and the Space Lua arithmetic model is aligned with Lua. Note that things like `-(expr)` in general may still produce results inconsistent with Lua. This cannot be fixed at parser level and must be fixed at runtime level which will need far more complex change to the Space Lua interpreter code. Therefor these cases we omitted from the tests. Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
307 lines
5.9 KiB
TypeScript
307 lines
5.9 KiB
TypeScript
type ASTContext = {
|
|
ctx: ASTCtx;
|
|
};
|
|
|
|
export type NumericType = "int" | "float";
|
|
|
|
export type ASTCtx = {
|
|
from?: number;
|
|
to?: number;
|
|
} & Record<string, any>;
|
|
|
|
export type LuaBlock = {
|
|
type: "Block";
|
|
statements: LuaStatement[];
|
|
} & ASTContext;
|
|
|
|
// STATEMENTS
|
|
export type LuaReturnStatement = {
|
|
type: "Return";
|
|
expressions: LuaExpression[];
|
|
} & ASTContext;
|
|
|
|
export type LuaStatement =
|
|
| LuaSemicolonStatement
|
|
| LuaLabelStatement
|
|
| LuaBreakStatement
|
|
| LuaGotoStatement
|
|
| LuaReturnStatement
|
|
| LuaBlock
|
|
| LuaWhileStatement
|
|
| LuaRepeatStatement
|
|
| LuaIfStatement
|
|
| LuaForStatement
|
|
| LuaForInStatement
|
|
| LuaFunctionStatement
|
|
| LuaLocalFunctionStatement
|
|
| LuaAssignmentStatement
|
|
| LuaLocalStatement
|
|
| LuaFunctionCallStatement;
|
|
|
|
export type LuaSemicolonStatement = {
|
|
type: "Semicolon";
|
|
} & ASTContext;
|
|
|
|
export type LuaLabelStatement = {
|
|
type: "Label";
|
|
name: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaBreakStatement = {
|
|
type: "Break";
|
|
} & ASTContext;
|
|
|
|
export type LuaGotoStatement = {
|
|
type: "Goto";
|
|
name: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaWhileStatement = {
|
|
type: "While";
|
|
condition: LuaExpression;
|
|
block: LuaBlock;
|
|
} & ASTContext;
|
|
|
|
export type LuaRepeatStatement = {
|
|
type: "Repeat";
|
|
block: LuaBlock;
|
|
condition: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaIfStatement = {
|
|
type: "If";
|
|
conditions: { condition: LuaExpression; block: LuaBlock }[];
|
|
elseBlock?: LuaBlock;
|
|
} & ASTContext;
|
|
|
|
export type LuaForStatement = {
|
|
type: "For";
|
|
name: string;
|
|
start: LuaExpression;
|
|
end: LuaExpression;
|
|
step?: LuaExpression;
|
|
block: LuaBlock;
|
|
} & ASTContext;
|
|
|
|
export type LuaForInStatement = {
|
|
type: "ForIn";
|
|
names: string[];
|
|
expressions: LuaExpression[];
|
|
block: LuaBlock;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionStatement = {
|
|
type: "Function";
|
|
name: LuaFunctionName;
|
|
body: LuaFunctionBody;
|
|
} & ASTContext;
|
|
|
|
export type LuaLocalFunctionStatement = {
|
|
type: "LocalFunction";
|
|
name: string;
|
|
body: LuaFunctionBody;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionName = {
|
|
type: "FunctionName";
|
|
propNames: string[];
|
|
colonName?: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionBody = {
|
|
type: "FunctionBody";
|
|
parameters: string[];
|
|
block: LuaBlock;
|
|
} & ASTContext;
|
|
|
|
export type LuaAssignmentStatement = {
|
|
type: "Assignment";
|
|
variables: LuaLValue[];
|
|
expressions: LuaExpression[];
|
|
} & ASTContext;
|
|
|
|
export type LuaLValue =
|
|
| LuaVariable
|
|
| LuaPropertyAccessExpression
|
|
| LuaTableAccessExpression;
|
|
|
|
export type LuaLocalStatement = {
|
|
type: "Local";
|
|
names: LuaAttName[];
|
|
expressions?: LuaExpression[];
|
|
} & ASTContext;
|
|
|
|
export type LuaAttName = {
|
|
type: "AttName";
|
|
name: string;
|
|
attribute?: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionCallStatement = {
|
|
type: "FunctionCallStatement";
|
|
call: LuaFunctionCallExpression;
|
|
} & ASTContext;
|
|
|
|
// EXPRESSIONS
|
|
export type LuaExpression =
|
|
| LuaNilLiteral
|
|
| LuaBooleanLiteral
|
|
| LuaNumberLiteral
|
|
| LuaStringLiteral
|
|
| LuaPrefixExpression
|
|
| LuaBinaryExpression
|
|
| LuaUnaryExpression
|
|
| LuaTableConstructor
|
|
| LuaFunctionDefinition
|
|
| LuaQueryExpression;
|
|
|
|
export type LuaNilLiteral = {
|
|
type: "Nil";
|
|
} & ASTContext;
|
|
|
|
export type LuaBooleanLiteral = {
|
|
type: "Boolean";
|
|
value: boolean;
|
|
} & ASTContext;
|
|
|
|
export type LuaNumberLiteral = {
|
|
type: "Number";
|
|
value: number;
|
|
numericType: NumericType;
|
|
} & ASTContext;
|
|
|
|
export type LuaStringLiteral = {
|
|
type: "String";
|
|
value: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaPrefixExpression =
|
|
| LuaVariableExpression
|
|
| LuaParenthesizedExpression
|
|
| LuaFunctionCallExpression;
|
|
|
|
export type LuaParenthesizedExpression = {
|
|
type: "Parenthesized";
|
|
expression: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaVariableExpression =
|
|
| LuaVariable
|
|
| LuaPropertyAccessExpression
|
|
| LuaTableAccessExpression;
|
|
|
|
export type LuaVariable = {
|
|
type: "Variable";
|
|
name: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaPropertyAccessExpression = {
|
|
type: "PropertyAccess";
|
|
object: LuaPrefixExpression;
|
|
property: string;
|
|
} & ASTContext;
|
|
|
|
export type LuaTableAccessExpression = {
|
|
type: "TableAccess";
|
|
object: LuaPrefixExpression;
|
|
key: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionCallExpression = {
|
|
type: "FunctionCall";
|
|
prefix: LuaPrefixExpression;
|
|
name?: string;
|
|
args: LuaExpression[];
|
|
} & ASTContext;
|
|
|
|
export type LuaBinaryExpression = {
|
|
type: "Binary";
|
|
operator: string;
|
|
left: LuaExpression;
|
|
right: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaUnaryExpression = {
|
|
type: "Unary";
|
|
operator: string;
|
|
argument: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaTableConstructor = {
|
|
type: "TableConstructor";
|
|
fields: LuaTableField[];
|
|
} & ASTContext;
|
|
|
|
export type LuaTableField =
|
|
| LuaDynamicField
|
|
| LuaPropField
|
|
| LuaExpressionField;
|
|
|
|
export type LuaDynamicField = {
|
|
type: "DynamicField";
|
|
key: LuaExpression;
|
|
value: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaPropField = {
|
|
type: "PropField";
|
|
key: string;
|
|
value: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaExpressionField = {
|
|
type: "ExpressionField";
|
|
value: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaFunctionDefinition = {
|
|
type: "FunctionDefinition";
|
|
body: LuaFunctionBody;
|
|
} & ASTContext;
|
|
|
|
// Query stuff
|
|
export type LuaQueryExpression = {
|
|
type: "Query";
|
|
clauses: LuaQueryClause[];
|
|
} & ASTContext;
|
|
|
|
export type LuaQueryClause =
|
|
| LuaFromClause
|
|
| LuaWhereClause
|
|
| LuaLimitClause
|
|
| LuaOrderByClause
|
|
| LuaSelectClause;
|
|
|
|
export type LuaFromClause = {
|
|
type: "From";
|
|
name?: string;
|
|
expression: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaWhereClause = {
|
|
type: "Where";
|
|
expression: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaLimitClause = {
|
|
type: "Limit";
|
|
limit: LuaExpression;
|
|
offset?: LuaExpression;
|
|
} & ASTContext;
|
|
|
|
export type LuaOrderByClause = {
|
|
type: "OrderBy";
|
|
orderBy: LuaOrderBy[];
|
|
} & ASTContext;
|
|
|
|
export type LuaOrderBy = {
|
|
type: "Order";
|
|
expression: LuaExpression;
|
|
direction: "asc" | "desc";
|
|
} & ASTContext;
|
|
|
|
export type LuaSelectClause = {
|
|
type: "Select";
|
|
expression: LuaExpression;
|
|
} & ASTContext;
|