UNPKG

@litexa/core

Version:

Litexa, a programming language for writing Alexa skills

143 lines (115 loc) 4.54 kB
### # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ### fs = require 'fs' path = require 'path' mkdirp = require 'mkdirp' peg = require 'pegjs' crypto = require 'crypto' debug = require('debug')('litexa') sourceFilename = "#{__dirname}/litexa.pegjs" cacheFilename = "#{__dirname}/litexa.pegjs.cached" parserSourceCode = null try hash = crypto.createHash('md5') sourcePEG = fs.readFileSync sourceFilename, 'utf8' hash.update(sourcePEG) sourceHash = hash.digest('hex') cached = JSON.parse(fs.readFileSync(cacheFilename, 'utf8')) if cached.hash == sourceHash parserSourceCode = cached.source debug "cached parser loaded" else debug "cached parser was state #{sourceHash} != #{cached.hash}" catch e debug "no cached parser found" debug e unless parserSourceCode source = fs.readFileSync(sourceFilename, 'utf8') parserSourceCode = peg.generate source, { cache: true, output: 'source', format: 'bare', allowedStartRules:['start', 'TestStatements'] } cached = hash: sourceHash source: parserSourceCode fs.writeFileSync cacheFilename, JSON.stringify(cached, null, 2), 'utf8' try parser = eval(parserSourceCode) catch e debug "failed to eval parser" throw e module.exports.parser = parser module.exports.sourceCode = parserSourceCode module.exports.buildExtendedParser = (projectInfo) -> enableParserCache = false if projectInfo.isMock enableParserCache = false # try to load the cache if enableParserCache tempdir = path.join projectInfo.root, '.deploy' mkdirp.sync tempdir projectSourceCacheFilename = path.join tempdir, 'extended-litexa.pegjs' projectCodeCacheFilename = path.join tempdir, 'extended-litexa.pegjs.cached' try extParserSource = fs.readFileSync projectCodeCacheFilename, 'utf8' extParser = eval extParserSource return extParser # interpolate in any extensions extSourcePEG = "" + sourcePEG statementNames = [] testStatementNames = [] intentStatementNames = [] for extensionName, extension of projectInfo.extensions continue unless extension.language? for statementName, statement of extension.language.statements statementNames.push statementName unless statement.parser? throw new Error "Statement #{statementName} in extension #{extensionName} is missing parser code" extSourcePEG += "\n#{statement.parser}\n" for statementName, statement of extension.language.testStatements testStatementNames.push statementName unless statement.parser? throw new Error "Test statement #{statementName} in extension #{extensionName} is missing parser code" extSourcePEG += "\n#{statement.parser}\n" replacePlaceholder = (placeholder, nameList) -> block = for s in nameList " / " + s extSourcePEG = extSourcePEG.replace placeholder, block.join '\n' replacePlaceholder " /* ADDITIONAL STATEMENTS */", statementNames replacePlaceholder " /* ADDITIONAL TEST STATEMENTS */", testStatementNames replacePlaceholder " /* ADDITIONAL INTENT STATEMENTS */", intentStatementNames # save the combined parser input for later if enableParserCache fs.writeFileSync projectSourceCacheFilename, extSourcePEG, 'utf8' extParserSource = peg.generate extSourcePEG, { cache: true, output: 'source', format: 'bare', allowedStartRules:['start', 'TestStatements', 'AllFileExclusions'] } try extParser = eval extParserSource catch err debug "failed to eval extended parser" throw e # success! Recycle the generated parser for later if enableParserCache fs.writeFileSync projectCodeCacheFilename, extParserSource, 'utf8' return extParser fragmentParser = null module.exports.parseFragment = (fragment, language) -> unless fragmentParser? source = fs.readFileSync sourceFilename, 'utf8' fragmentParserSource = peg.generate source, cache: true output: 'source' format: 'bare' allowedStartRules:['Fragment'] fragmentParser = eval(fragmentParserSource) result = null skill = pushCode: (thing) -> result = thing getExtensions: -> {} returnValue = fragmentParser.parse fragment, skill: skill lib: require './parserlib.coffee' language: language ? 'default' result = returnValue unless result? return result