Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed major bug with cons_context on cursor. Made working indent comb…

…inator.
  • Loading branch information...
commit 7df4eac935812fe4a0c446e5c7f14d94a8e2d161 1 parent 6592e07
@luqui authored
View
7 StructuralEditor.js
@@ -56,7 +56,7 @@ var NormalMode = object({
mode_container.text('Normal');
},
keydown: function(e) {
- var head = typeof(this.zipper.expr) === 'string' ? new SF.SynClass({}) : this.zipper.expr.head;
+ var head = typeof(this.zipper.expr) === 'string' ? SF.SynClass : this.zipper.expr.head;
var self = this;
var navigate = function(dir) {
@@ -127,7 +127,8 @@ var InsertMode = object({
},
render: function() {
code_container.empty();
- code_container.append(elt('pre', {}, SF.render_cursor(this.cursor, text_node(this.input_buffer))));
+ var newel = elt('pre', {}, SF.render_cursor(this.cursor, $(text_node(this.input_buffer))));
+ code_container.append(newel);
},
update: function(c) {
if (!c) return;
@@ -136,7 +137,7 @@ var InsertMode = object({
},
});
-var TopCls = new SF.SynClass({});
+var TopCls = SF.SynClass;
mode = new NormalMode(new SF.Zipper([], TopCls.make([top_node])));
View
31 StructuralFramework.js
@@ -141,19 +141,15 @@ $$.Expr = object({
// A SynClass represents a syntactic class, and can go at the head of an Expr. Creating
// a SynClass is the same as subclassing it; i.e.:
//
-// new SynClass({
+// inherit(SynClass, {
// method_1: function(x) {...}
// method_2: function(x,y) {...}
// })
//
// In addition to the methods here, SynClasses require a 'parse_prefix' method,
-// which are a tokenizer (codecatalog.net/379/) returning a Cursor (see below),
+// which returns a tokenizer (codecatalog.net/379/) returning a Cursor (see below),
// positioned just after the parsed token.
-$$.SynClass = object({
- init: function(opts) {
- extend(this, opts);
- },
-
+$$.SynClass = {
// Make takes Exprs/strings for args and constructs an Expr with this class
// at the head. Note that this function takes a list, it is not variadic.
make: function(args) {
@@ -163,13 +159,16 @@ $$.SynClass = object({
// Render takes a *pre_rendered* argument for each argument in the Expr's
// args. It's up to this function just to stitch them together.
render: function() {
- return arguments_to_array(arguments);
+ // XXX yuck, there *has* to be a better way to do this.
+ var s = $([]);
+ foreach(arguments, function(arg) { s = s.add(arg) });
+ return s;
},
nav_up: function(zipper) { return zipper.up() },
nav_down: function(zipper) { return zipper.down(0) },
nav_left: function(zipper) { return zipper.left() },
nav_right: function(zipper) { return zipper.right() }
-});
+};
// A Context is just like an Expr, except that exactly one of its args has a "hole"
@@ -276,7 +275,7 @@ $$.Cursor = object({
parse_insert: function(text) {
var expr = this.zipper.expr;
- var tokresult = expr.args[this.pos].head.parse_prefix(text);
+ var tokresult = expr.args[this.pos].head.parse_prefix()(text);
if (tokresult) {
var newcursor = tokresult[0];
var thiscx = context_in(expr, this.pos);
@@ -291,21 +290,17 @@ $$.Cursor = object({
}
},
cons_context: function(cx) {
- var cxs = [cx].concat(this.zipper.contexts);
+ var cxs = this.zipper.contexts.concat([cx]);
return new $$.Cursor(new $$.Zipper(cxs, this.zipper.expr), this.pos);
}
});
var render_head = function(head, args) {
- var ret = elt('span');
- foreach(head.render.apply(head, args), function(arg) {
- ret.append(arg);
- });
- return ret;
+ return elt('span', {}, head.render.apply(head, args));
};
var render_expr_tree = function(expr) {
- if (typeof(expr) === 'string') return text_node(expr);
+ if (typeof(expr) === 'string') return $(text_node(expr));
var args = [];
foreach(expr.args, function(arg) {
@@ -345,7 +340,7 @@ $$.render_cursor = function(cursor, ins) {
var r = render_expr_tree(a);
return i == cursor.pos ? $(ins).add(elt('span', {'class': 'cursor_selected'}, r)) : r;
});
- if (cursor.pos == cursor.zipper.expr.length) {
+ if (cursor.pos == cursor.zipper.expr.args.length) {
args[args.length-1] = elt('span', {'class': 'cursor_selected_right'}, args[args.length-1], ins);
}
var h = render_head(cursor.zipper.expr.head, args);
View
121 StructuralGrammar.js
@@ -132,10 +132,10 @@ var nonempty_choice_tokenizer = function(tokenizers) {
// CodeCatalog Snippet http://www.codecatalog.net/392/1/
var wrap_fields = function(wrapper, dict) {
- var ret = {};
- for_kv(dict, function(k,v) {
- ret[k] = k in wrapper ? wrapper[k](v) : v;
- });
+ var ret = { constructor: dict.constructor };
+ for (var k in dict) {
+ ret[k] = k in wrapper ? wrapper[k](dict[k]) : dict[k];
+ }
return ret;
};
// End CodeCatalog Snippet
@@ -166,14 +166,11 @@ var $$ = {};
// this should be separated into two concepts: classes of actual exprs,
// and classes of expr generators, or something.
var box_synclass = function(cls) {
- return new SF.SynClass({
+ return inherit(SF.SynClass, {
render: function() {
return elt('span', {'class': 'box'}, text_node(' '));
},
- parse_prefix: cls.parse_prefix,
- parse_insert: function() {
- return cls.parse_prefix;
- }
+ parse_prefix: cls.parse_prefix
});
};
@@ -186,14 +183,15 @@ var cursor = function(expr, pos) {
};
$$.empty = function(grammar) {
- var c = new SF.SynClass({
+ return inherit(SF.SynClass, {
open: function() { return this.make([]) },
- parse_prefix: function(str) {
- // XXX cursor violates nonempty invariant
- return [ cursor(c.make([]), 0), str ]
- }
- });
- return c;
+ parse_prefix: method(function(self) {
+ return function(str) {
+ // XXX cursor violates nonempty invariant
+ return [ cursor(self.make([]), 0), str ]
+ }
+ })
+ })
};
$$.cls = function(clsname, syn) {
@@ -206,17 +204,65 @@ $$.cls = function(clsname, syn) {
};
};
+// CodeCatalog Snippet http://www.codecatalog.net/385/2/
+var extend = function(target, src) {
+ for (var k in src) {
+ target[k] = src[k];
+ }
+ return target;
+};
+// End CodeCatalog Snippet
+
+// CodeCatalog Snippet http://www.codecatalog.net/359/1/
+var trace = function() {
+ console.log.apply(console, arguments);
+ return arguments[arguments.length-1];
+};
+// End CodeCatalog Snippet
+
+var inherit = function(o, newmethods) {
+ var F = function() {};
+ F.prototype = o;
+ return extend(new F(), newmethods);
+};
+
+var method = function(m) {
+ return function() {
+ var args = [this].concat(arguments);
+ return m.apply(this, args);
+ };
+};
+
+$$.indent = function(syn) {
+ return function(grammar) {
+ return inherit(SF.SynClass, {
+ open: function() { return this.make([syn(grammar).open()]) },
+ render: function() {
+ var subelt = this.__proto__.render.apply(this, arguments);
+ return elt('div', {'class': 'indented'}, subelt);
+ },
+ parse_prefix: function() {
+ var self = this;
+ return map_tokenizer(function(t) {
+ return t.cons_context(new SF.Context(self, [null]));
+ }, syn(grammar).parse_prefix());
+ }
+ });
+ };
+};
+
$$.literal = function(str) {
return function(grammar) {
- var c = new SF.SynClass({
+ return inherit(SF.SynClass, {
open: function() {
- return c.make([str]);
+ return this.make([str]);
},
- parse_prefix: string_tokenizer(str, function() {
- return cursor(c.make([str]), 1);
+ parse_prefix: method(function(self) {
+ return string_tokenizer(str, function() {
+ return cursor(self.make([str]), 1);
+ })
})
});
- return c;
};
};
@@ -227,11 +273,10 @@ $$.token = function(rx, canon) {
var tok = typeof(canon) === 'undefined' ? m[0] : canon;
return cursor($$.literal(m[0])(grammar).make([tok]), 1);
};
- var c = new SF.SynClass({
- open: function() { return box_synclass(c).make([]) },
- parse_prefix: regexp_tokenizer(toks)
+ return inherit(SF.SynClass, {
+ open: function() { return box_synclass(this).make([]) },
+ parse_prefix: function() { return regexp_tokenizer(toks) }
});
- return c;
};
};
@@ -239,20 +284,20 @@ $$.seq = function() {
var xs = arguments_to_array(arguments);
return function(grammar) {
var get_subsyms = function() { return xs.map(function(x) { return x(grammar) }) };
- var c = new SF.SynClass({
+ return inherit(SF.SynClass, {
open: function() {
return this.make(get_subsyms().map(function(x) { return x.open() }));
},
- parse_prefix: function(str) {
+ parse_prefix: method(function(self) { return function(str) {
var subsyms = get_subsyms();
var rs = subsyms.map(function(x) { return x.open() });
for (var i = 0; i < subsyms.length; i++) {
- var tokresult = subsyms[i].parse_prefix(str);
+ var tokresult = subsyms[i].parse_prefix()(str);
if (tokresult) {
rs[i] = tokresult[0];
if (tokresult[1].length < str.length) { // consumed input
rs[i] = null;
- var newcx = new SF.Context(c, rs);
+ var newcx = new SF.Context(self, rs);
return [ tokresult[0].cons_context(newcx), tokresult[1] ]
}
}
@@ -261,10 +306,9 @@ $$.seq = function() {
}
}
// no input consumed. the sequence accepts the empty string.
- return [ cursor(c.make(rs), rs.length), str ];
- }
+ return [ cursor(self.make(rs), rs.length), str ];
+ } })
});
- return c;
};
};
@@ -274,15 +318,16 @@ $$.choice = function() {
var xs = arguments_to_array(arguments);
return function(grammar) {
- var c = new SF.SynClass({
+ return inherit(SF.SynClass, {
open: function() {
- return box_synclass(c).make([]);
+ return box_synclass(this).make([]);
},
- parse_prefix: nonempty_choice_tokenizer(xs.map(function(x) {
- return x(grammar).parse_prefix
- }))
+ parse_prefix: function() {
+ return nonempty_choice_tokenizer(xs.map(function(x) {
+ return x(grammar).parse_prefix()
+ }))
+ }
});
- return c;
};
};
View
18 demo/structural.html
@@ -13,6 +13,7 @@
.cursor_selected { border-left: 1px solid blue }
.cursor_selected_right { border-right: 1px solid blue }
.modeline { font-weight: bold }
+ .indented { margin-left: 4em }
</style>
<script>
@@ -60,12 +61,27 @@
var text_node = function(text) { return document.createTextNode(text) };
// End CodeCatalog Snippet
+// CodeCatalog Snippet http://www.codecatalog.net/16/3/
+var elt = function(name, attrs) {
+ var r = $(document.createElement(name));
+ if (attrs) {
+ for (var i in attrs) {
+ r.attr(i, attrs[i]);
+ }
+ }
+ for (var i = 2; i < arguments.length; ++i) {
+ r.append(arguments[i]);
+ }
+ return r;
+};
+// End CodeCatalog Snippet
+
var space = SG.token(/\s*/, ' ');
var top_class = SG.grammar('stmts', {
'stmts': SG.choice(
SG.empty,
- SG.seq(SG.sym('stmt'), SG.token(/;/, ';\n'), SG.sym('stmts'))),
+ SG.seq(SG.sym('stmt'), SG.token(/;/, ';\n'), SG.indent(SG.sym('stmts')))),
'stmt': SG.choice(
SG.sym('var_decl'),
SG.sym('funcall')),
Please sign in to comment.
Something went wrong with that request. Please try again.