UNPKG

walt-compiler

Version:

Alternative syntax for WebAssembly text format

332 lines (303 loc) 7.08 kB
// Node Types import { extendNode } from '../../utils/extend-node'; import Syntax from 'walt-syntax'; import { nonEmpty, drop } from './helpers'; const marker = lexer => { const { col, line } = lexer; if (!lexer.lines.length) { return { col, line, sourceLine: '' }; } return { col, line, sourceLine: lexer.lines[lexer.line - 1], }; }; export default function factory(lexer) { const node = (Type, seed = {}) => d => { const params = d.filter(nonEmpty); const { value = '', meta = {} } = seed; const start = marker(lexer); const end = params[params.length - 1] && params[params.length - 1].range ? params[params.length - 1].range[1] : { ...start, col: start.col + value.length }; return { value, type: null, Type, toString() {}, meta, range: [start, end], params, }; }; const binary = d => { const [lhs, operator, rhs] = d.filter(nonEmpty); let Type = Syntax.BinaryExpression; if (operator.value === '||' || operator.value === '&&') { Type = Syntax.Select; } return node(Type, { value: operator.value })([lhs, rhs]); }; const constant = d => { const value = d[0].value; return extendNode( { value: `${value}`, type: value.toString().indexOf('.') !== -1 ? 'f32' : 'i32', }, node(Syntax.Constant)([]) ); }; const identifier = d => node('Identifier', { value: d.join('') })([]); const declaration = Type => d => { const [pair, ...init] = drop(d); const [id, type] = pair.params; return extendNode( { value: id.value, type: type.value, }, node(Type)(init) ); }; const unary = ([operator, target]) => { let params = [target]; if (operator.value === '-') { params = [ { ...target, value: '0', Type: Syntax.Constant, params: [], meta: {}, }, target, ]; } return extendNode( { value: operator.value, params, }, node(Syntax.UnaryExpression)([operator, target]) ); }; const ternary = d => { return extendNode( { value: '?', }, node(Syntax.TernaryExpression)(d) ); }; const subscript = d => { const [id, field] = d.filter(nonEmpty); return extendNode( { value: id.value, params: [id, field], }, node(Syntax.ArraySubscript)([id, field]) ); }; const fun = d => { const [name, args, result, block] = d.filter(nonEmpty); return { ...name, Type: Syntax.FunctionDeclaration, meta: [], params: [args, result, block], }; }; const voidFun = d => { const params = drop(d); const [name, args, block] = params; const result = extendNode({ type: null }, node(Syntax.FunctionResult)([])); return extendNode( { value: name.value, params: [args, result, block], }, node(Syntax.FunctionDeclaration)(params) ); }; const result = d => { const [type] = drop(d); return extendNode( { type: type != null && type.value !== 'void' ? type.value : null, }, node(Syntax.FunctionResult)(d) ); }; const call = d => { let [id, ...params] = drop(d); return extendNode( { value: id.value, }, node(Syntax.FunctionCall)([id, ...params]) ); }; const struct = d => { const [id, ...params] = drop(d); return extendNode( { value: id.value, }, node(Syntax.Struct)(params) ); }; const typedef = d => { const [id, args, res] = drop(d); return extendNode( { value: id.value, params: [ node(Syntax.FunctionArguments)(args), extendNode( { type: res.value, }, node(Syntax.FunctionResult)([res]) ), ], type: res.type, }, node(Syntax.Typedef)([id, args, result]) ); }; const string = d => { return extendNode( { value: d[0].value, type: 'i32', }, node(Syntax.StringLiteral)([]) ); }; return { node, binary, constant, identifier, unary, ternary, subscript, access(d) { return extendNode( { value: d[0].value + '.' + d[1].value, }, node(Syntax.Access)(d) ); }, fun, declaration, call, struct, result, string, char(d) { return extendNode( { value: d[0].value, type: 'i32', }, node(Syntax.CharacterLiteral)([]) ); }, type(d) { return extendNode( { value: d[0].value, type: d[0].value, params: [], }, node(Syntax.Type)(d) ); }, arrayType(d) { // d => ({ ...d[0], value: d[0].value + "[]", type: d[0].type + "[]" }) const p = drop(d); const type = p[0]; return extendNode( { value: type.value + '[]', type: type.type + '[]', params: [], }, node(Syntax.ArrayType)(d) ); }, typeGeneric(d) { const [id, obj] = drop(d); return extendNode( { value: id.value, type: id.value, params: [obj], }, node(Syntax.Type)(d) ); }, typedef, voidFun, assignment(d, value) { if (['-=', '+='].includes(value)) { const operator = value[0]; const [target, amount] = drop(d); const b = binary([target, { value: operator }, amount]); return node(Syntax.Assignment, { value: '=', })([target, b]); } return node(Syntax.Assignment, { value })(d); }, assignmentExpr(d, value) { if (['-=', '+='].includes(value)) { const operator = value[0]; const [target, amount] = drop(d); const b = binary([target, { value: operator }, amount]); return node(Syntax.AssignmentExpression, { value: '=', })([target, b]); } return node(Syntax.AssignmentExpression, { value })(d); }, forLoop(d) { const [initializer, condition, afterthought, ...body] = drop(d); return node(Syntax.Loop)([initializer, condition, ...body, afterthought]); }, whileLoop(d) { const noop = node(Syntax.Noop)([]); return node(Syntax.Loop)([noop, ...d]); }, spread(d) { return node(Syntax.Spread)(d); }, builtinDecl(d) { const [id, typeNode] = drop(d); return extendNode( { value: id.value, type: typeNode.value, params: [typeNode], }, node(Syntax.ImmutableDeclaration)(d) ); }, addressOf(d) { const [id] = drop(d); return extendNode( { value: id.value, params: [], }, node('AddressOf')(d) ); }, }; }