rework parsing; add support for parentheses.
This commit is contained in:
parent
98757ce023
commit
fd1bb299d4
|
@ -91,7 +91,3 @@ here are the commands that are specific to this REPL:
|
|||
- `!.exit` exits the REPL.
|
||||
- `!.env` prints out all the named functions.
|
||||
- `!.clear` clears the console.
|
||||
|
||||
## parentheses
|
||||
|
||||
catgirl calculus supports using parentheses to group things. this implementation currently does not support this, thus it is non-compliant.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import Line from "./Line.mjs";
|
||||
import Expr from "./Expr.mjs";
|
||||
|
||||
import { tokenize_line } from "./tokenize.mjs";
|
||||
|
||||
const Invalid = "invalid";
|
||||
|
||||
const Program = {
|
||||
|
@ -27,18 +29,6 @@ export function parse (code) {
|
|||
}
|
||||
|
||||
export function parse_line (line) {
|
||||
if (line.length === 0) {
|
||||
return {
|
||||
type: Line.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
if (line[0] === "#") {
|
||||
return {
|
||||
type: Line.Comment,
|
||||
};
|
||||
}
|
||||
|
||||
if (line[0] === "!") {
|
||||
return {
|
||||
type: Line.Special,
|
||||
|
@ -46,7 +36,13 @@ export function parse_line (line) {
|
|||
};
|
||||
}
|
||||
|
||||
const tokens = line.split(/\s+/g).filter(t => t.length > 0);
|
||||
const tokens = tokenize_line(line);
|
||||
|
||||
if (tokens.length === 0) {
|
||||
return {
|
||||
type: Line.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
if (tokens.length >= 3 && tokens[1] === "=") {
|
||||
return parse_binding(tokens);
|
||||
|
@ -67,8 +63,6 @@ function parse_binding (tokens) {
|
|||
|
||||
if (tokens.length < 3) return invalid();
|
||||
|
||||
// TODO: handle parentheses here.
|
||||
|
||||
const name = tokens[0];
|
||||
if (!is_valid_name(name)) return invalid();
|
||||
|
||||
|
@ -88,6 +82,7 @@ function parse_binding (tokens) {
|
|||
}
|
||||
|
||||
function is_valid_name (name) {
|
||||
if (typeof name !== "string") return false;
|
||||
if (name.length === 0) return false;
|
||||
if (name[0] === "#" || name[0] === "!") return false;
|
||||
if (name === "=") return false;
|
||||
|
@ -114,16 +109,19 @@ function Token (value) {
|
|||
}
|
||||
|
||||
function parse_expression (tokens) {
|
||||
if (!Array.isArray(tokens)) {
|
||||
return Token(tokens);
|
||||
}
|
||||
if (tokens.length === 1) {
|
||||
return Token(tokens[0]);
|
||||
}
|
||||
|
||||
if (tokens.length === 0) {
|
||||
return {
|
||||
type: Expr.Invalid,
|
||||
};
|
||||
}
|
||||
|
||||
if (tokens.length === 1) {
|
||||
return Token(tokens[0]);
|
||||
}
|
||||
|
||||
if (tokens.some(is_right_arrow)) {
|
||||
return parse_function (tokens);
|
||||
}
|
||||
|
@ -165,8 +163,8 @@ function parse_application (tokens) {
|
|||
if (tokens.length === 2) {
|
||||
return {
|
||||
type: Expr.Application,
|
||||
fn: Token(tokens[0]),
|
||||
arg: Token(tokens[1]),
|
||||
fn: parse_expression(tokens[0]),
|
||||
arg: parse_expression(tokens[1]),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
import Line from "./Line.mjs";
|
||||
|
||||
|
||||
|
||||
export function tokenize_line (line) {
|
||||
const tree = [];
|
||||
const stack = [];
|
||||
let node = tree;
|
||||
let token = "";
|
||||
|
||||
function push (value) { node.push(value); }
|
||||
function push_token () {
|
||||
if (token.length > 0) {
|
||||
push(token);
|
||||
token = "";
|
||||
}
|
||||
}
|
||||
|
||||
const chars = line.split("");
|
||||
for (const c of chars) {
|
||||
if (is_parens_open(c)) {
|
||||
push_token();
|
||||
|
||||
stack.push(node);
|
||||
node.push([]);
|
||||
node = node[node.length - 1];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_parens_close(c)) {
|
||||
push_token();
|
||||
node = stack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_whitespace(c)) {
|
||||
push_token();
|
||||
continue;
|
||||
}
|
||||
|
||||
token += c;
|
||||
}
|
||||
|
||||
push_token();
|
||||
return tree;
|
||||
}
|
||||
|
||||
function is_parens_open (c) {
|
||||
return c === "(";
|
||||
}
|
||||
|
||||
function is_parens_close (c) {
|
||||
return c === ")";
|
||||
}
|
||||
|
||||
function is_whitespace (c) {
|
||||
return /\s/.test(c);
|
||||
}
|
||||
|
||||
function exclude_comments (line) {
|
||||
return line[0] !== "#";
|
||||
}
|
||||
|
Loading…
Reference in New Issue