UNPKG

walt-compiler

Version:

Alternative syntax for WebAssembly text format

103 lines (91 loc) 3.33 kB
/** * Default Arguments syntax sugar plugin. * * Converts FUNCTION CALLS with missing arguments to default values * * @flow */ import Syntax from 'walt-syntax'; // $FlowFixMe import grammar from './default-arguments.ne'; import walkNode from 'walt-parser-tools/walk-node'; import type { SemanticPlugin, GrammarPlugin } from '../flow/types'; export default function(): SemanticPlugin & GrammarPlugin { return { grammar, semantics() { return { [Syntax.FunctionDeclaration]: next => args => { const [node, context] = args; const [argumentsNode] = node.params; const defaultArguments = []; walkNode({ Assignment: defaultArg => { const [, value] = defaultArg.params; defaultArguments.push(value); }, })(argumentsNode); // Attach any default arguments found to the function node directly, // proceed with the rest of the parsers return next([ { ...node, meta: { ...node.meta, DEFAULT_ARGUMENTS: defaultArguments }, }, context, ]); }, // There isn't a need to parse out the Assignment expressions as they are // not actually compiled/generated into the final binary // [Syntax.Assignment]: next => (args, transform) => { // const [node, context] = args; // // Not inside arguments // const currentScope = current(context.scopes); // // Arguments have not been set for scope yet and the current scope is // // not global // if (currentScope.arguments == null && context.scopes.length > 1) { // return next(args); // } // // Assignment has higher precedence than ":" Pair expressions so the // // children of this node will be [Pair(id:type), Constant(value)] // // remove the constant return the pair. // // // // A helpful visual of a valid default argument syntax: // // // // function fn(x : i32, y : i32, z : i32 = 0) { ... } // const [pair] = node.params; // // Short circuit the parsers since it does not make sense to process // // assignment anymore. Instead parse the Pair, which is the argument. // return transform([pair, context]); // }, [Syntax.FunctionCall]: next => args => { const [call, context] = args; const { functions } = context; const [id, ...fnArgs] = call.params; const target = functions[id.value]; // Most likely a built-in function if (!target) { return next(args); } const expectedArguments = target.meta.FUNCTION_METADATA.argumentsCount; const count = fnArgs.length; const difference = expectedArguments - count; if (difference > 0) { return next([ { ...call, params: [ ...call.params, ...target.meta.DEFAULT_ARGUMENTS.slice(difference - 1), ], }, context, ]); } return next(args); }, }; }, }; }