123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- const Node = require('./node')
- const tokenTypes = require('./tokenTypes')
-
- module.exports = class Parser {
- constructor(tokenStream) {
- this.tokenStream = tokenStream
- }
-
- parse() {
- let tree = []
- while (this.tokenStream.peek().type !== tokenTypes.EOF) {
- tree.push(this.expr())
- }
- return tree
- }
-
- expr() {
- this.tokenStream.eat(tokenTypes.OPAREN)
-
- let elementNode = new Node()
- elementNode.type = 'functionCall'
- elementNode.functionName = this.tokenStream.eat(tokenTypes.LITERAL).value
- elementNode.args = []
- elementNode.subtree = []
-
- while (
- this.tokenStream.peek().type != tokenTypes.CPAREN &&
- this.tokenStream.peek().type !== tokenTypes.EOF
- ) {
- if (this.tokenStream.peek().type === tokenTypes.ATTRIBUTE) {
- elementNode.args.push(this.attribute())
- } else if (this.tokenStream.peek().type === tokenTypes.OPAREN) {
- elementNode.subtree.push(this.expr())
- } else if (this.tokenStream.peek().type === tokenTypes.LITERAL) {
- elementNode.subtree.push(this.identifier())
- } else if (this.tokenStream.peek().type === tokenTypes.QUOTE) {
- elementNode.subtree.push(this.quotedString())
- } else if (this.tokenStream.peek().type === tokenTypes.KEYWORD) {
- elementNode.subtree.push(this.keyword())
- }
- }
-
- this.tokenStream.eat(tokenTypes.CPAREN)
-
- return elementNode
- }
-
- attribute() {
- let attributeNode = new Node()
- attributeNode.attributeName = this.tokenStream.eat(
- tokenTypes.ATTRIBUTE,
- ).value
- if (this.tokenStream.peek().type === tokenTypes.QUOTE) {
- attributeNode.attributeValue = this.quotedString()
- } else if (this.tokenStream.peek().type === tokenTypes.LITERAL) {
- attributeNode.attributeValue = this.identifier()
- }
-
- return attributeNode
- }
-
- identifier() {
- const identifier = this.tokenStream.eat(tokenTypes.LITERAL)
- return new Node({
- type: 'identifier',
- name: identifier.value,
- })
- }
-
- quotedString() {
- return new Node({
- type: 'string',
- content: this.string(),
- })
- }
-
- keyword() {
- const keyword = this.tokenStream.eat(tokenTypes.KEYWORD)
-
- if (keyword.value === 'each') {
- const subject = this.identifier()
- const symbol = this.tokenStream.eat(tokenTypes.SYMBOL)
- const body = this.expr()
- return new Node({
- type: 'each',
- symbol: symbol,
- body: body,
- subject: subject,
- })
- }
- }
-
- string() {
- this.tokenStream.eat(tokenTypes.QUOTE)
- let stringValue = this.tokenStream.eat(tokenTypes.LITERAL).value
- this.tokenStream.eat(tokenTypes.QUOTE)
- return stringValue
- }
- }
|