/src/script/parser.ne
@preprocessor typescript @{% import * as moo from 'moo'; import { SayInstruction } from './say'; import { MenuInstruction } from './menu'; import { Label } from './label'; import { GotoInstruction } from './goto'; import { FinishInstruction } from './finish'; import { ClearScreenInstruction } from './clear'; import { SleepInstruction } from './sleep'; import { PauseInstruction } from './pause'; import { MoveInstruction } from './move'; import { Direction, directionFromToken } from '../direction'; const lexer = moo.compile({ ws: { match: /[ \t\r\n]+/, lineBreaks: true }, number: /[0-9]+(?:\.[0-9]+)?/, keyword: ['say', 'menu', 'item', 'end', 'exit', 'goto', 'if', 'finish', 'clear', 'buy', 'transact', 'setflag', 'move'], direction: /\+(?:n|e|s|w|north|east|south|west)/, label: /[a-zA-Z_][a-zA-Z0-9_]*:/, word: /[a-zA-Z_][a-zA-Z0-9_]*/, dqstring: { match: /"(?:\\["\\]|[^\n"\\])*"/, value: s => s.slice(1, -1) }, sqstring: { match: /'(?:\\['\\]|[^\n'\\])*'/, value: s => s.slice(1, -1) }, mlstring: { match: /\[\[\[[^]*?\]\]\]/, lineBreaks: true, value: s => s.slice(3, -3).trim() }, bang: '!', flag_mark: '$', obj_mark: '@', comma: ',', }); %} @lexer lexer program -> __:? statement:* {% data => data[1] || data[0] %} statement -> "say" __ string __ {% data => new SayInstruction(data[2]) %} statement -> "menu" __ menuitem:* "end" __ {% data => new MenuInstruction(data[2]) %} statement -> %label __ {% data => new Label(data[0].value.slice(0, -1)) %} statement -> "goto" __ %word __ {% data => new GotoInstruction(data[2].value) %} statement -> "finish" __ {% data => new FinishInstruction() %} statement -> "clear" __ {% data => new ClearScreenInstruction() %} statement -> "sleep" __ number __ {% data => new SleepInstruction(data[2]) %} statement -> "pause" __ string __ {% data => new PauseInstruction(data[2]) %} statement -> "move" __ direction __ {% data => new MoveInstruction(data[2]) %} statement -> "move" __ number _ %comma _ number __ {% data => new MoveInstruction(data[2], data[6]) %} menuitem -> if:? "item" __ string __ program "end" __ menuitem -> if:? "buy" __ obj_identifier __ number __ menuitem -> if:? "exit" __ string __ if -> "if" __ %bang:? flag_identifier __ if -> "if" __ %bang:? obj_identifier __ flag_identifier -> %flag_mark %word obj_identifier -> %obj_mark %word number -> %number {% data => parseFloat(data[0]) %} string -> %dqstring {% data => data[0].value %} string -> %sqstring {% data => data[0].value %} string -> %mlstring {% data => data[0].value %} direction -> %direction {% data => directionFromToken(data[0]) %} __ -> %ws {% _ => null %} _ -> null | %ws {% _ => null %}