UNPKG

mercury-lang

Version:

Parser for the mercury live coding language

90 lines (79 loc) 2.71 kB
//==================================================================== // Mercury parser // // Parse a textfile of Mercury code and return the .json syntax tree // written by Timo Hoogland 2021, www.timohoogland.com //==================================================================== const nearley = require('nearley'); const grammar = require('./mercuryGrammar.js'); const worker = require('./mercuryTraverser.js'); const DEBUG = false; function mercuryParser(code=''){ // split multiple lines into array of strings let lines = code.includes('\r\n')? code.split('\r\n') : code.split('\n'); let syntaxTree = { '@main' : [] }; let errors = []; let warnings = []; let parseTree = {}; let parser; for (let l=0; l<lines.length; l++){ // let line = lines[l].trim(); if (lines[l].trim() !== ''){ // create a Parser object from our grammar parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar), { keepHistory: false }); try { // parse something! parser.feed(lines[l]) // parser.results is an array of possible parsings. if (DEBUG){ console.log('parsing:', lines[l]); if (parser.results.length > 1){ console.log("Warning, ambiguous grammar!"); for (var i=0; i<results; i++){ // console.log("Result", i+1, "of", results, "\n", util.inspect(parser.results[i], { depth: 10 }), "\n"); console.log(parser.results[i]); } } else { console.log(parser.results[0]); } } // only if not undefined if (parser.results[0] !== undefined){ // add line number and code to new object if it is one if (parser.results[0]?.['@object']?.['@new']){ parser.results[0]['@object']['@new']['@line'] = l+1; // parser.results[0]['@object']['@new']['@code'] = lines[l]; } // build the tokenized syntax tree syntaxTree['@main'].push(parser.results[0]); } else { throw new Error(); } } catch (e) { // console.error(e); let err = `Error at line ${Number(l)+1}`; try { err += `: Unexpected ${e.token.type}: '${e.token.value}' at ${lines[l].slice(0, e.token.offset)}${e.token.text}<-`; } catch (e) {} if (DEBUG){ console.error(err); } errors.push(err); } } } // traverse Syntax Tree and create Intermediate Representation parseTree = worker.traverseTreeIR(syntaxTree['@main']); errors = parseTree.errors.concat(errors); delete parseTree.errors; warnings = parseTree.warnings; delete parseTree.warnings; // return both the parseTree and syntaxTree in one object return { 'parseTree': parseTree, 'syntaxTree': syntaxTree, 'errors': errors, 'warnings' : warnings }; } exports.mercuryParser = mercuryParser;