Skip to content

Commit

Permalink
implement local type inference
Browse files Browse the repository at this point in the history
  • Loading branch information
Gusarich committed Mar 27, 2024
1 parent 7ef2ae1 commit 8db8a3d
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 7 deletions.
19 changes: 19 additions & 0 deletions src/generator/writers/writeFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,25 @@ export function writeStatement(f: ASTStatement, self: string | null, returns: Ty

ctx.append(`${resolveFuncType(t, ctx)} ${id(f.name)} = ${writeCastedExpression(f.expression, t, ctx)};`);
return;
} else if (f.kind === 'statement_let_no_type') {

const varType = getExpType(ctx.ctx, f.expression);

// Contract/struct case
if (varType.kind === 'ref') {
const tt = getType(ctx.ctx, varType.name);
if (tt.kind === 'contract' || tt.kind === 'struct') {
if (varType.optional) {
ctx.append(`tuple ${id(f.name)} = ${writeCastedExpression(f.expression, varType, ctx)};`);
} else {
ctx.append(`var ${resolveFuncTypeUnpack(varType, id(f.name), ctx)} = ${writeCastedExpression(f.expression, varType, ctx)};`);
}
return;
}
}

ctx.append(`${resolveFuncType(varType, ctx)} ${id(f.name)} = ${writeCastedExpression(f.expression, varType, ctx)};`);
return;
} else if (f.kind === 'statement_assign') {

// Prepare lvalue
Expand Down
15 changes: 13 additions & 2 deletions src/grammar/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,14 @@ export type ASTStatementLet = {
ref: ASTRef
}

export type ASTStatementLetNoType = {
kind: 'statement_let_no_type',
id: number,
name: string,
expression: ASTExpression,
ref: ASTRef
}

export type ASTStatementReturn = {
kind: 'statement_return',
id: number,
Expand Down Expand Up @@ -431,8 +439,8 @@ export type ASTStatementRepeat = {
// Unions
//

export type ASTStatement = ASTStatementLet | ASTStatementReturn | ASTStatementExpression | ASTSTatementAssign | ASTSTatementAugmentedAssign | ASTCondition | ASTStatementWhile | ASTStatementUntil | ASTStatementRepeat;
export type ASTNode = ASTExpression | ASTProgram | ASTStruct | ASTField | ASTContract | ASTArgument | ASTFunction | ASTOpCall | ASTStatementLet | ASTStatementReturn | ASTProgram | ASTPrimitive | ASTOpCallStatic | ASTStatementExpression | ASTNativeFunction | ASTSTatementAssign | ASTSTatementAugmentedAssign | ASTOpNew | ASTNewParameter | ASTTypeRef | ASTNull | ASTCondition | ASTInitFunction | ASTStatementWhile | ASTStatementUntil | ASTStatementRepeat | ASTReceive | ASTLvalueRef | ASTString | ASTTrait | ASTProgramImport | ASTFunction | ASTNativeFunction | ASTInitOf | ASTString | ASTConstant;
export type ASTStatement = ASTStatementLet | ASTStatementLetNoType | ASTStatementReturn | ASTStatementExpression | ASTSTatementAssign | ASTSTatementAugmentedAssign | ASTCondition | ASTStatementWhile | ASTStatementUntil | ASTStatementRepeat;
export type ASTNode = ASTExpression | ASTProgram | ASTStruct | ASTField | ASTContract | ASTArgument | ASTFunction | ASTOpCall | ASTStatementLet | ASTStatementLetNoType | ASTStatementReturn | ASTProgram | ASTPrimitive | ASTOpCallStatic | ASTStatementExpression | ASTNativeFunction | ASTSTatementAssign | ASTSTatementAugmentedAssign | ASTOpNew | ASTNewParameter | ASTTypeRef | ASTNull | ASTCondition | ASTInitFunction | ASTStatementWhile | ASTStatementUntil | ASTStatementRepeat | ASTReceive | ASTLvalueRef | ASTString | ASTTrait | ASTProgramImport | ASTFunction | ASTNativeFunction | ASTInitOf | ASTString | ASTConstant;
export type ASTExpression = ASTOpBinary | ASTOpUnary | ASTOpField | ASTNumber | ASTID | ASTBoolean | ASTOpCall | ASTOpCallStatic | ASTOpNew | ASTNull | ASTLvalueRef | ASTInitOf | ASTString | ASTConditional;
export type ASTType = ASTPrimitive | ASTStruct | ASTContract | ASTTrait;

Expand Down Expand Up @@ -557,6 +565,9 @@ export function traverse(node: ASTNode, callback: (node: ASTNode) => void) {
traverse(node.type, callback);
traverse(node.expression, callback);
}
if (node.kind === 'statement_let_no_type') {
traverse(node.expression, callback);
}
if (node.kind === 'statement_return') {
if (node.expression) {
traverse(node.expression, callback);
Expand Down
5 changes: 5 additions & 0 deletions src/grammar/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export function cloneNode<T extends ASTNode>(src: T): T {
type: cloneASTNode(src.type),
expression: cloneNode(src.expression),
});
} else if (src.kind === 'statement_let_no_type') {
return cloneASTNode({
...src,
expression: cloneNode(src.expression),
});
} else if (src.kind === 'statement_condition') {
return cloneASTNode({
...src,
Expand Down
3 changes: 2 additions & 1 deletion src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ Tact {
| StatementRepeat
| StatementUntil
StatementBlock = "{" Statement* "}"
StatementLet = let id ":" Type "=" Expression ";"
StatementLet = let id ":" Type "=" Expression ";" --withType
| let id "=" Expression ";" --withoutType
StatementReturn = return Expression ";" --withExpression
| return ";" --withoutExpression
StatementExpression = Expression ";"
Expand Down
4 changes: 3 additions & 1 deletion src/grammar/grammar.ohm-bundle.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ export interface TactActionDict<T> extends ActionDict<T> {
ReceiveFunction?: (this: NonterminalNode, arg0: NonterminalNode) => T;
Statement?: (this: NonterminalNode, arg0: NonterminalNode) => T;
StatementBlock?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T;
StatementLet?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode, arg4: TerminalNode, arg5: NonterminalNode, arg6: TerminalNode) => T;
StatementLet_withType?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode, arg4: TerminalNode, arg5: NonterminalNode, arg6: TerminalNode) => T;
StatementLet_withoutType?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: TerminalNode, arg3: NonterminalNode, arg4: TerminalNode) => T;
StatementLet?: (this: NonterminalNode, arg0: NonterminalNode) => T;
StatementReturn_withExpression?: (this: NonterminalNode, arg0: NonterminalNode, arg1: NonterminalNode, arg2: TerminalNode) => T;
StatementReturn_withoutExpression?: (this: NonterminalNode, arg0: NonterminalNode, arg1: TerminalNode) => T;
StatementReturn?: (this: NonterminalNode, arg0: NonterminalNode) => T;
Expand Down
2 changes: 1 addition & 1 deletion src/grammar/grammar.ohm-bundle.js

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions src/grammar/grammar.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import rawGrammar from './grammar.ohm-bundle';
import { ASTConstantAttribute, ASTContractAttribute, ASTFunctionAttribute, ASTNode, ASTProgram, ASTRef, ASTString, ASTTypeRef, createNode, createRef, inFile, throwError } from './ast';
import { ASTConstantAttribute, ASTContractAttribute, ASTExpression, ASTFunctionAttribute, ASTNode, ASTProgram, ASTRef, ASTString, ASTTypeRef, createNode, createRef, inFile, throwError } from './ast';
import { checkVariableName } from './checkVariableName';
import { TactSyntaxError } from './../errors';
import { MatchResult } from 'ohm-js';
import { TypeOrigin } from '../types/types';
import { checkFunctionAttributes } from './checkFunctionAttributes';
import { checkConstAttributes } from './checkConstAttributes';
import { getExpType } from '../types/resolveExpression';

let ctx: { origin: TypeOrigin } | null;

Expand Down Expand Up @@ -428,7 +429,7 @@ semantics.addOperation<ASTNode>('resolve_declaration', {

// Statements
semantics.addOperation<ASTNode>('resolve_statement', {
StatementLet(_arg0, arg1, _arg2, arg3, _arg4, arg5, _arg6) {
StatementLet_withType(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
checkVariableName(arg1.sourceString, createRef(arg1));

return createNode({
Expand All @@ -439,6 +440,16 @@ semantics.addOperation<ASTNode>('resolve_statement', {
ref: createRef(this)
})
},
StatementLet_withoutType(arg0, arg1, arg2, arg3, arg4) {
checkVariableName(arg1.sourceString, createRef(arg1));

return createNode({
kind: 'statement_let_no_type',
name: arg1.sourceString,
expression: arg3.resolve_expression(),
ref: createRef(this)
})
},
StatementReturn_withExpression(_arg0, arg1, _arg2) {
return createNode({
kind: 'statement_return',
Expand Down
Loading

0 comments on commit 8db8a3d

Please sign in to comment.