Skip to content

Commit

Permalink
feat: Add Function && RETURN
Browse files Browse the repository at this point in the history
  • Loading branch information
liulinboyi committed Feb 27, 2021
1 parent 8596f91 commit 3496461
Show file tree
Hide file tree
Showing 14 changed files with 483 additions and 12 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Comment ::= Ignored "#" SourceCharacter // 注释
BinaryExpression::= (Variable | Number) Ignored Operator Ignored (Variable | Number)
Operator ::= "+" | "-" | "*" | "/"
BinaryExpressions ::= (BinaryExpression Operator)+ Ignored (Variable | Number) // eg: 1: (2 + 1 +) 3 2: ((2 + 1 +) (5 + 6 -)) 3
FunctionDeclaration ::= "func" Ignored Name Ignored "(" Variable ("," Variable)* ")" BlockStatement // eg: 1: func foo ($a) {} 2: func foo ($a[,$b][,$c]) {} ("," Variable)*这部分是一个或多个
BlockStatement ::= "{" Ignored ReturnStatement Ignored "}"
ReturnStatement ::= "return" BinaryExpression
CallFunction ::= Name "(" (Variable | Number) ("," (Variable | Number))* ")" Ignored
```

Expand Down
8 changes: 8 additions & 0 deletions demo/hello-world-5.pineapple
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

func add($a,$b) {
return $a + $b
}

$res = add(1,2)

print($res)
33 changes: 31 additions & 2 deletions dist/src/lexer1.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NewLexer = exports.Lexer = exports.tokenNameMap = exports.keywords = exports.Operator = exports.SourceCharacter = exports.COMMENT = exports.STRING = exports.NUMBER = exports.INTERGER = exports.TOKEN_IGNORED = exports.TOKEN_PRINT = exports.TOKEN_NAME = exports.TOKEN_DUOQUOTE = exports.TOKEN_QUOTE = exports.TOKEN_EQUAL = exports.TOKEN_RIGHT_PAREN = exports.TOKEN_LEFT_PAREN = exports.TOKEN_VAR_PREFIX = exports.TOKEN_EOF = exports.Tokens = void 0;
exports.NewLexer = exports.Lexer = exports.tokenNameMap = exports.keywords = exports.TOKEN_FUNC_PARAMS_DIV = exports.TOKEN_RETURN = exports.BLOCK_END = exports.BLOCK_START = exports.TOKEN_FUNC = exports.Operator = exports.SourceCharacter = exports.COMMENT = exports.STRING = exports.NUMBER = exports.INTERGER = exports.TOKEN_IGNORED = exports.TOKEN_PRINT = exports.TOKEN_NAME = exports.TOKEN_DUOQUOTE = exports.TOKEN_QUOTE = exports.TOKEN_EQUAL = exports.TOKEN_RIGHT_PAREN = exports.TOKEN_LEFT_PAREN = exports.TOKEN_VAR_PREFIX = exports.TOKEN_EOF = exports.Tokens = void 0;
// token const
var Tokens;
(function (Tokens) {
Expand All @@ -20,8 +20,13 @@ var Tokens;
Tokens[Tokens["COMMENT"] = 13] = "COMMENT";
Tokens[Tokens["SourceCharacter"] = 14] = "SourceCharacter";
Tokens[Tokens["Operator"] = 15] = "Operator";
Tokens[Tokens["TOKEN_FUNC"] = 16] = "TOKEN_FUNC";
Tokens[Tokens["BLOCK_START"] = 17] = "BLOCK_START";
Tokens[Tokens["BLOCK_END"] = 18] = "BLOCK_END";
Tokens[Tokens["TOKEN_RETURN"] = 19] = "TOKEN_RETURN";
Tokens[Tokens["TOKEN_FUNC_PARAMS_DIV"] = 20] = "TOKEN_FUNC_PARAMS_DIV"; // ,
})(Tokens = exports.Tokens || (exports.Tokens = {}));
exports.TOKEN_EOF = Tokens.TOKEN_EOF, exports.TOKEN_VAR_PREFIX = Tokens.TOKEN_VAR_PREFIX, exports.TOKEN_LEFT_PAREN = Tokens.TOKEN_LEFT_PAREN, exports.TOKEN_RIGHT_PAREN = Tokens.TOKEN_RIGHT_PAREN, exports.TOKEN_EQUAL = Tokens.TOKEN_EQUAL, exports.TOKEN_QUOTE = Tokens.TOKEN_QUOTE, exports.TOKEN_DUOQUOTE = Tokens.TOKEN_DUOQUOTE, exports.TOKEN_NAME = Tokens.TOKEN_NAME, exports.TOKEN_PRINT = Tokens.TOKEN_PRINT, exports.TOKEN_IGNORED = Tokens.TOKEN_IGNORED, exports.INTERGER = Tokens.INTERGER, exports.NUMBER = Tokens.NUMBER, exports.STRING = Tokens.STRING, exports.COMMENT = Tokens.COMMENT, exports.SourceCharacter = Tokens.SourceCharacter, exports.Operator = Tokens.Operator;
exports.TOKEN_EOF = Tokens.TOKEN_EOF, exports.TOKEN_VAR_PREFIX = Tokens.TOKEN_VAR_PREFIX, exports.TOKEN_LEFT_PAREN = Tokens.TOKEN_LEFT_PAREN, exports.TOKEN_RIGHT_PAREN = Tokens.TOKEN_RIGHT_PAREN, exports.TOKEN_EQUAL = Tokens.TOKEN_EQUAL, exports.TOKEN_QUOTE = Tokens.TOKEN_QUOTE, exports.TOKEN_DUOQUOTE = Tokens.TOKEN_DUOQUOTE, exports.TOKEN_NAME = Tokens.TOKEN_NAME, exports.TOKEN_PRINT = Tokens.TOKEN_PRINT, exports.TOKEN_IGNORED = Tokens.TOKEN_IGNORED, exports.INTERGER = Tokens.INTERGER, exports.NUMBER = Tokens.NUMBER, exports.STRING = Tokens.STRING, exports.COMMENT = Tokens.COMMENT, exports.SourceCharacter = Tokens.SourceCharacter, exports.Operator = Tokens.Operator, exports.TOKEN_FUNC = Tokens.TOKEN_FUNC, exports.BLOCK_START = Tokens.BLOCK_START, exports.BLOCK_END = Tokens.BLOCK_END, exports.TOKEN_RETURN = Tokens.TOKEN_RETURN, exports.TOKEN_FUNC_PARAMS_DIV = Tokens.TOKEN_FUNC_PARAMS_DIV;
// regex match patterns
const regexName = /^[_\d\w]+/;
// 关键字
Expand All @@ -45,6 +50,11 @@ exports.tokenNameMap = {
[exports.COMMENT]: "COMMENT",
[exports.SourceCharacter]: "SourceCharacter",
[exports.Operator]: "Operator",
[exports.TOKEN_FUNC]: "TOKEN_FUNC",
[exports.BLOCK_START]: "BLOCK_START",
[exports.BLOCK_END]: "BLOCK_END",
[exports.TOKEN_RETURN]: "TOKEN_RETURN",
[exports.TOKEN_FUNC_PARAMS_DIV]: "TOKEN_FUNC_PARAMS_DIV",
};
class Lexer {
constructor(sourceCode, lineNum, nextToken, nextTokenType, nextTokenLineNum) {
Expand Down Expand Up @@ -168,6 +178,25 @@ class Lexer {
case '#':
this.skipSourceCode(1);
return { lineNum: this.lineNum, tokenType: exports.COMMENT, token: "#" };
case ",":
this.skipSourceCode(1);
return { lineNum: this.lineNum, tokenType: exports.TOKEN_FUNC_PARAMS_DIV, token: "," };
case "{":
this.skipSourceCode(1);
return { lineNum: this.lineNum, tokenType: exports.BLOCK_START, token: "{" };
case "}":
this.skipSourceCode(1);
return { lineNum: this.lineNum, tokenType: exports.BLOCK_END, token: "}" };
}
// return
if (this.sourceCode[0] === 'r' && this.sourceCode.slice(0, 6) === 'return') {
this.skipSourceCode(6);
return { lineNum: this.lineNum, tokenType: exports.TOKEN_RETURN, token: "return" };
}
// func
if (this.sourceCode[0] === 'f' && this.sourceCode.slice(0, 4) === "func") {
this.skipSourceCode(4);
return { lineNum: this.lineNum, tokenType: exports.TOKEN_FUNC, token: "func" };
}
// Operator
if (/\+|\-|\*|\//.test(this.sourceCode[0])) {
Expand Down
9 changes: 8 additions & 1 deletion dist/src/parser.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = exports.parseString = exports.parseNumber = exports.parseVariable = exports.Program = void 0;
exports.parse = exports.parseString = exports.parseNumber = exports.parseName = exports.parseVariable = exports.Program = void 0;
const lexer1_1 = require("./lexer1");
const Comment_1 = require("./parser/Comment");
const Print_1 = require("./parser/Print");
const Assignment_1 = require("./parser/Assignment");
const Function_1 = require("./parser/Function");
const Expression_1 = require("./parser/Expression");
class Program {
constructor(type, body, LineNum) {
this.type = 'Program';
Expand Down Expand Up @@ -46,6 +48,10 @@ function parseStatement(lexer) {
return Assignment_1.parseAssignment(lexer);
case lexer1_1.COMMENT:
return Comment_1.paseComment(lexer);
case lexer1_1.TOKEN_FUNC:
return Function_1.parseFunction(lexer);
case lexer1_1.TOKEN_NAME:
return Expression_1.parseExpression(lexer);
default:
throw new Error("parseStatement(): unknown Statement.");
}
Expand All @@ -68,6 +74,7 @@ function parseName(lexer) {
let { nowLineNum: _, nowToken: name } = lexer.NextTokenIs(lexer1_1.TOKEN_NAME);
return name;
}
exports.parseName = parseName;
// Integer ::= [0-9]+
// Number ::= Integer Ignored
function parseNumber(lexer) {
Expand Down
12 changes: 10 additions & 2 deletions dist/src/parser/Assignment.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0;
exports.parseBinaryExpression = exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0;
const lexer1_1 = require("../lexer1");
const parser_1 = require("../parser");
const Expression_1 = require("./Expression");
class Literal {
constructor(value, type = 'Literal') {
this.type = type;
Expand Down Expand Up @@ -71,7 +72,13 @@ function parseAssignment(lexer) {
}
}
else {
if (tokenType === lexer1_1.NUMBER) {
if (tokenType === lexer1_1.TOKEN_NAME) { // 函数执行并赋值
const expression = Expression_1.parseExpression(lexer);
console.log(expression);
VariableDeclarator.init = expression.expression;
assignment.type = "VariableDeclaration";
}
else if (tokenType === lexer1_1.NUMBER) {
// console.log('parseNumber start')
const literial = new Literal(parser_1.parseNumber(lexer)); // 这里面会把邻近的空格回车删掉
VariableDeclarator.init = literial;
Expand Down Expand Up @@ -138,3 +145,4 @@ function parseBinaryExpression(lexer, idAndinit, assignment, leftType) {
assignment.declarations.push(VariableDeclarator);
return assignment;
}
exports.parseBinaryExpression = parseBinaryExpression;
44 changes: 44 additions & 0 deletions dist/src/parser/Expression.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseExpression = void 0;
const lexer1_1 = require("../lexer1");
const parser_1 = require("../parser");
const Assignment_1 = require("./Assignment");
function parseExpression(lexer) {
const ExpressionStatement = {
type: "ExpressionStatement",
expression: {
type: "CallExpression",
callee: {
type: "Identifier",
},
arguments: []
}
};
const IdentifierName = parser_1.parseName(lexer);
ExpressionStatement.expression.callee.name = IdentifierName;
lexer.NextTokenIs(lexer1_1.TOKEN_LEFT_PAREN); // (
const params = [];
const tokenType = lexer.LookAhead().tokenType;
while (tokenType !== lexer1_1.TOKEN_RIGHT_PAREN) {
let p;
// $
if (tokenType === lexer1_1.TOKEN_VAR_PREFIX) {
p = parser_1.parseVariable(lexer);
params.push(new Assignment_1.Identifier(p));
}
else if (tokenType === lexer1_1.NUMBER) {
p = parser_1.parseNumber(lexer);
params.push(new Assignment_1.Literal(p));
}
if (lexer.nextTokenType === lexer1_1.TOKEN_RIGHT_PAREN) {
break;
}
lexer.NextTokenIs(lexer1_1.TOKEN_FUNC_PARAMS_DIV); // ,
}
lexer.NextTokenIs(lexer1_1.TOKEN_RIGHT_PAREN); // )
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 空格
ExpressionStatement.expression.arguments = params;
return ExpressionStatement;
}
exports.parseExpression = parseExpression;
136 changes: 136 additions & 0 deletions dist/src/parser/Function.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.paseReturnStatement = exports.paseBlock = exports.parseFunction = void 0;
const lexer1_1 = require("../lexer1");
const parser_1 = require("../parser");
const Assignment_1 = require("./Assignment");
function parseFunction(lexer) {
const FunctionDeclaration = {
type: "FunctionDeclaration",
id: {
type: "Identifier",
},
params: [
// {
// type: "Identifier",
// name: ""
// }
],
body: {
type: "BlockStatement",
body: [
// {
// type: "ReturnStatement",
// argument: {
// type: "BinaryExpression",
// left: {
// },
// operator: '+',
// right: {
// }
// }
// }
]
}
};
lexer.NextTokenIs(lexer1_1.TOKEN_FUNC);
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 空格
const Identifier = parser_1.parseName(lexer);
FunctionDeclaration.id.name = Identifier;
lexer.NextTokenIs(lexer1_1.TOKEN_LEFT_PAREN); // (
const params = [];
while (lexer.LookAhead().tokenType !== lexer1_1.TOKEN_RIGHT_PAREN) {
const p = parser_1.parseVariable(lexer);
params.push(p);
if (lexer.nextTokenType === lexer1_1.TOKEN_RIGHT_PAREN) {
break;
}
lexer.NextTokenIs(lexer1_1.TOKEN_FUNC_PARAMS_DIV);
}
for (let item of params) {
FunctionDeclaration.params.push({
type: "Identifier",
name: item.Name
});
}
lexer.NextTokenIs(lexer1_1.TOKEN_RIGHT_PAREN); // )
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 去除空格回车等
lexer.NextTokenIs(lexer1_1.BLOCK_START);
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); // 去除空格回车等
const block = paseBlock(lexer);
FunctionDeclaration.body.body.push({
type: "ReturnStatement",
argument: block.declarations[0].init
});
lexer.NextTokenIs(lexer1_1.BLOCK_END);
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED);
return FunctionDeclaration;
}
exports.parseFunction = parseFunction;
function paseBlock(lexer) {
const ahead = lexer.LookAhead();
if (ahead.tokenType === lexer1_1.TOKEN_RETURN) {
lexer.NextTokenIs(lexer1_1.TOKEN_RETURN);
lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED);
return paseReturnStatement(lexer);
}
}
exports.paseBlock = paseBlock;
function paseReturnStatement(lexer) {
let assignment = new Assignment_1.Assignment();
assignment.LineNum = lexer.GetLineNum();
assignment.declarations = [];
let VariableDeclarator = { type: "VariableDeclarator" };
VariableDeclarator.id = { type: "Identifier" };
const tokenType = lexer.LookAhead().tokenType;
console.log(tokenType, 'lexer.LookAhead().tokenType');
// 如果后面仍是$
if (tokenType === lexer1_1.TOKEN_VAR_PREFIX) {
const Variable = parser_1.parseVariable(lexer); // 标识符,这里面会把邻近的空格回车删掉
console.log(Variable, 'Variable');
const identifier = new Assignment_1.Identifier(Variable.Name);
VariableDeclarator.init = identifier;
assignment.type = "VariableDeclaration";
assignment.declarations.push(VariableDeclarator); // 一行只允许声明和初始化一个变量
let ahead = lexer.LookAhead();
console.log(ahead, 'parseAssignment Variable ahead');
if (ahead.tokenType !== lexer1_1.Operator) {
return assignment;
}
else {
lexer.NextTokenIs(lexer1_1.Operator); // +-*/
// lexer.LookAheadAndSkip(TOKEN_IGNORED) // 空格
lexer.isIgnored();
const idAndinit = assignment.declarations.pop();
return Assignment_1.parseBinaryExpression(lexer, idAndinit, assignment, "Identifier");
}
}
else {
if (tokenType === lexer1_1.NUMBER) {
// console.log('parseNumber start')
const literial = new Assignment_1.Literal(parser_1.parseNumber(lexer)); // 这里面会把邻近的空格回车删掉
VariableDeclarator.init = literial;
assignment.type = "VariableDeclaration";
// console.log('parseNumber end')
}
else {
const literial = new Assignment_1.Literal(parser_1.parseString(lexer)); // 这里面会把邻近的空格回车删掉
VariableDeclarator.init = literial;
assignment.type = "VariableDeclaration";
}
assignment.declarations.push(VariableDeclarator); // 一行只允许声明和初始化一个变量
let ahead = lexer.LookAhead();
console.log(ahead, 'parseAssignment not Variable ahead');
if (ahead.tokenType !== lexer1_1.Operator) {
return assignment;
}
else {
lexer.NextTokenIs(lexer1_1.Operator); // +-*/
// lexer.LookAheadAndSkip(TOKEN_IGNORED); // 空格
lexer.isIgnored();
const idAndinit = assignment.declarations.pop();
return Assignment_1.parseBinaryExpression(lexer, idAndinit, assignment, "Literal");
}
}
}
exports.paseReturnStatement = paseReturnStatement;
2 changes: 1 addition & 1 deletion dist/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const fs = require('fs');
const path = require('path');
const Execute = require('../dist/src/backend.js').Execute;
code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-4.pineapple'), { encoding: 'utf-8' });
code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-5.pineapple'), { encoding: 'utf-8' });
console.log(code, 'code');
if (code.length > 0) {
Execute(code);
Expand Down
Loading

0 comments on commit 3496461

Please sign in to comment.