Skip to content

Commit

Permalink
closes #144; implemented implements
Browse files Browse the repository at this point in the history
  • Loading branch information
satyr committed Jul 4, 2012
1 parent 6e2105e commit 1b3c163
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 75 deletions.
35 changes: 23 additions & 12 deletions lib/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -2059,12 +2059,12 @@ exports.Import = Import = (function(superclass){
exports.Of = Of = (function(superclass){
Of.displayName = 'Of';
var prototype = __extend(Of, superclass).prototype, constructor = Of;
__importAll(prototype, arguments[1]);
function Of(item, array){
this.item = item;
this.array = array;
}
prototype.children = ['item', 'array'];
__importAll(prototype, Negatable);
prototype.compileNode = function(o){
var array, items, code, sub, ref, cmp, cnj, i, test, __ref, __len;
items = (array = this.array.expandSlice(o).unwrap()).items;
Expand Down Expand Up @@ -2098,18 +2098,18 @@ exports.Of = Of = (function(superclass){
}
};
return Of;
}(Node));
}(Node, Negatable));
exports.Existence = Existence = (function(superclass){
Existence.displayName = 'Existence';
var prototype = __extend(Existence, superclass).prototype, constructor = Existence;
__importAll(prototype, arguments[1]);
function Existence(it, negated){
var __this = this instanceof __ctor ? this : new __ctor;
__this.it = it;
__this.negated = negated;
return __this;
} function __ctor(){} __ctor.prototype = prototype;
prototype.children = ['it'];
__importAll(prototype, Negatable);
prototype.compileNode = function(o){
var node, code, op, eq, __ref;
node = (__ref = this.it.unwrap(), __ref.front = this.front, __ref);
Expand All @@ -2129,7 +2129,7 @@ exports.Existence = Existence = (function(superclass){
}
};
return Existence;
}(Node));
}(Node, Negatable));
exports.Fun = Fun = (function(superclass){
Fun.displayName = 'Fun';
var prototype = __extend(Fun, superclass).prototype, constructor = Fun;
Expand Down Expand Up @@ -2288,31 +2288,32 @@ exports.Fun = Fun = (function(superclass){
exports.Class = Class = (function(superclass){
Class.displayName = 'Class';
var prototype = __extend(Class, superclass).prototype, constructor = Class;
function Class(title, sup, body){
function Class(title, sup, mixins, body){
this.title = title;
this.sup = sup;
this.mixins = mixins;
this.fun = Fun([], body);
}
prototype.children = ['title', 'sup', 'fun'];
prototype.children = ['title', 'sup', 'mixins', 'fun'];
prototype.isCallable = YES;
prototype.ripName = function(it){
this.name = it.varName();
};
prototype.compile = function(o, level){
var fun, title, decl, name, lines, i, node, proto, prop, f, ctor, vname, that, args, clas, __len, __i, __ref, __len1, __ref1, __j, __len2;
fun = this.fun, title = this.title;
var fun, body, lines, title, decl, name, proto, i, node, prop, f, ctor, vname, args, that, imports, clas, __len, __i, __ref, __len1, __ref1, __j, __len2, __res;
fun = this.fun, body = fun.body, lines = body.lines, title = this.title;
decl = title != null ? title.varName() : void 8;
name = decl || this.name;
if (ID.test(name || '')) {
fun.cname = name;
} else {
name = 'constructor';
}
lines = fun.body.lines;
proto = Var('prototype');
for (i = 0, __len = lines.length; i < __len; ++i) {
node = lines[i];
if (node instanceof Obj) {
lines[i] = Import(proto || (proto = Var('prototype')), node);
lines[i] = Import(proto, node);
for (__i = 0, __len1 = (__ref = node.items).length; __i < __len1; ++__i) {
prop = __ref[__i];
if ((__ref1 = prop.key) instanceof Key || __ref1 instanceof Literal) {
Expand All @@ -2336,11 +2337,21 @@ exports.Class = Class = (function(superclass){
ctor.ctor = true;
ctor.statement = true;
lines.push(vname = fun.proto = Var(fun.bound = name));
args = [];
if (that = this.sup) {
args = [that];
args.push(that);
fun.proto = Util.Extends(vname, (__ref = fun.params)[__ref.length] = Var('superclass'));
}
fun.cname && fun.body.prepend(Literal(name + ".displayName = '" + name + "'"));
if (that = this.mixins) {
__res = [];
for (__i = 0, __len = that.length; __i < __len; ++__i) {
args[args.length] = that[__i];
__res.push(Import(proto, JS("arguments[" + (args.length - 1) + "]"), true));
}
imports = __res;
body.prepend.apply(body, imports);
}
fun.cname && body.prepend(Literal(name + ".displayName = '" + name + "'"));
clas = Parens(Call.make(fun, args), true);
if (decl && title.isComplex()) {
clas = Assign(vname, clas);
Expand Down
36 changes: 23 additions & 13 deletions lib/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,20 +170,23 @@ bnf = {
return new Try($2, $3, $4, $6);
}), o('TRY Block FINALLY Block', function(){
return new Try($2, null, null, $4);
}), o('CLASS Block', function(){
return new Class(null, null, $2);
}), o('CLASS EXTENDS Expression Block', function(){
return new Class(null, $3, $4);
}), o('CLASS Chain Block', function(){
return new Class($2.unwrap(), null, $3);
}), o('CLASS Chain EXTENDS Expression Block', function(){
return new Class($2.unwrap(), $4, $5);
}), o('CLASS Chain OptExtends OptImplements Block', function(){
return new Class($2.unwrap(), $3, $4, $5);
}), o('CLASS OptExtends OptImplements Block', function(){
return new Class(null, $2, $3, $4);
}), o('Chain EXTENDS Expression', function(){
return Util.Extends($1.unwrap(), $3);
}), o('LABEL Expression', function(){
return new Label($1, $2);
}), o('LABEL Block', ditto)
],
Exprs: [
o('Expression', function(){
return [$1];
}), o('Exprs , Expression', function(){
return $1.concat($3);
})
],
KeyValue: [
o('Key'), o('LITERAL', function(){
return Prop(L(Key($1, $1 !== 'arguments' && $1 !== 'eval')), L(Literal($1)));
Expand Down Expand Up @@ -312,11 +315,18 @@ bnf = {
return $1.concat(new Case($3, $4));
})
],
Exprs: [
o('Expression', function(){
return [$1];
}), o('Exprs , Expression', function(){
return $1.concat($3);
OptExtends: [
o('EXTENDS Expression', function(){
return $2;
}), o('', function(){
return null;
})
],
OptImplements: [
o('IMPLEMENTS Exprs', function(){
return $2;
}), o('', function(){
return null;
})
]
};
Expand Down
4 changes: 2 additions & 2 deletions lib/lexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1363,8 +1363,8 @@ function indexOfPair(tokens, i){
}
return -1;
}
KEYWORDS_SHARED = ['true', 'false', 'null', 'this', 'void', 'super', 'return', 'throw', 'break', 'continue', 'if', 'else', 'for', 'while', 'switch', 'case', 'default', 'try', 'catch', 'finally', 'class', 'extends', 'new', 'do', 'delete', 'typeof', 'in', 'instanceof', 'import', 'function', 'let', 'with', 'var', 'const', 'export', 'debugger'];
KEYWORDS_UNUSED = ['enum', 'implements', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield'];
KEYWORDS_SHARED = ['true', 'false', 'null', 'this', 'void', 'super', 'return', 'throw', 'break', 'continue', 'if', 'else', 'for', 'while', 'switch', 'case', 'default', 'try', 'catch', 'finally', 'function', 'class', 'extends', 'implements', 'new', 'do', 'delete', 'typeof', 'in', 'instanceof', 'let', 'with', 'var', 'const', 'import', 'export', 'debugger'];
KEYWORDS_UNUSED = ['enum', 'interface', 'package', 'private', 'protected', 'public', 'static', 'yield'];
KEYWORDS = KEYWORDS_SHARED.concat(KEYWORDS_UNUSED);
ID = /((?!\d)(?:(?!\s)[\w$\xAA-\uFFDC])+)([^\n\S]*:(?![:=]))?|/g;
SYMBOL = /[-+*\/%&|^:]=|\.{1,3}|([+&|:])\1|\([^\n\S]*\)|-[->]|[!=]==?|~>|@@|<\[(?:[\s\S]*?\]>)?|<(?:<(?:=|<{0,2})|[-~])|>>>?=?|[<>]\??=?|!\?|=>|\*\*=?|[^\s#]?/g;
Expand Down
34 changes: 19 additions & 15 deletions lib/parser.js

Large diffs are not rendered by default.

29 changes: 15 additions & 14 deletions src/ast.co
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ exports.fromJSON = function
return node
if it.length? then fromJSON v for v of it else it

#### Modules
#### Mixins

Negatable =
show : -> @negated and \!
Expand Down Expand Up @@ -1257,13 +1257,11 @@ class exports.Import extends Node
#### Of
# Handles `of` operation that tests if the left operand is included within
# the right operand, arraywise.
class exports.Of extends Node
class exports.Of extends Node implements Negatable
(@item, @array) ->

children: <[ item array ]>

::<<<< Negatable

compileNode: (o) ->
{items} = array = @array.expandSlice(o)unwrap!
if array not instanceof Arr or items.length < 2
Expand All @@ -1286,13 +1284,11 @@ class exports.Of extends Node

#### Existence
# Checks a value for existence--not `undefined` nor `null`.
class exports.Existence extends Node
class exports.Existence extends Node implements Negatable
(@it, @negated) ~>

children: [\it]

::<<<< Negatable

compileNode: (o) ->
node = @it.unwrap! <<< {@front}
code = node.compile o, LEVEL_OP + PREC\==
Expand Down Expand Up @@ -1403,23 +1399,23 @@ class exports.Fun extends Node

#### Class
class exports.Class extends Node
(@title, @sup, body) -> @fun = Fun [] body
(@title, @sup, @mixins, body) -> @fun = Fun [] body

children: <[ title sup fun ]>
children: <[ title sup mixins fun ]>

isCallable: YES

ripName: !-> @name = it.varName!

compile: (o, level) ->
{fun, title} = this
{{{lines}:body}:fun, title} = this
decl = title?varName!
name = decl or @name
if ID.test name || '' then fun.cname = name else name = \constructor
{lines} = fun.body
proto = Var \prototype
for node, i of lines
if node instanceof Obj
lines[i] = Import proto||=Var(\prototype), node
lines[i] = Import proto, node
for prop of node.items
if prop.key instanceof [Key, Literal]
if prop.val instanceof Fun
Expand All @@ -1432,10 +1428,15 @@ class exports.Class extends Node
ctor ||= lines.* = Fun!
ctor <<< {name, +ctor, +statement}
lines.push vname = fun.proto = Var fun.bound = name
args = []
if @sup
args = [that]
args.push that
fun.proto = Util.Extends vname, fun.params.* = Var \superclass
fun.cname and fun.body.prepend Literal "#name.displayName = '#name'"
if @mixins
imports = for args.* of that
Import proto, JS("arguments[#{args.length-1}]"), true
body.prepend ...imports
fun.cname and body.prepend Literal "#name.displayName = '#name'"
clas = Parens Call.make(fun, args), true
clas = Assign vname, clas if decl and title.isComplex!
clas = Assign title, clas if title
Expand Down
22 changes: 15 additions & 7 deletions src/grammar.co
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,20 @@ bnf =
o 'TRY Block CATCH Block FINALLY Block' -> new Try $2, $3, $4, $6
o 'TRY Block FINALLY Block' -> new Try $2, null null $4

o 'CLASS Block' -> new Class null null $2
o 'CLASS EXTENDS Expression Block' -> new Class null $3, $4
o 'CLASS Chain Block' -> new Class $2.unwrap!, null $3
o 'CLASS Chain EXTENDS Expression Block' -> new Class $2.unwrap!, $4, $5
o 'CLASS Chain OptExtends OptImplements Block'
, -> new Class $2.unwrap!, $3, $4, $5
o 'CLASS OptExtends OptImplements Block'
, -> new Class null , $2, $3, $4

o 'Chain EXTENDS Expression' -> Util.Extends $1.unwrap!, $3

o 'LABEL Expression' -> new Label $1, $2
o 'LABEL Block' ditto

Exprs:
o \Expression -> [$1]
o 'Exprs , Expression' -> $1.concat $3

# The various forms of property.
KeyValue:
o \Key
Expand Down Expand Up @@ -300,9 +304,13 @@ bnf =
o 'CASE Exprs Block' -> [new Case $2, $3]
o 'Cases CASE Exprs Block' -> $1.concat new Case $3, $4

Exprs:
o \Expression -> [$1]
o 'Exprs , Expression' -> $1.concat $3
OptExtends:
o 'EXTENDS Expression' -> $2
o '' -> null

OptImplements:
o 'IMPLEMENTS Exprs' -> $2
o '' -> null

# Precedence and Associativity
# ----------------------------
Expand Down
8 changes: 4 additions & 4 deletions src/lexer.co
Original file line number Diff line number Diff line change
Expand Up @@ -896,15 +896,15 @@ function indexOfPair tokens, i
# Keywords that Coco shares in common with JavaScript.
KEYWORDS_SHARED = <[
true false null this void super return throw break continue
if else for while switch case default try catch finally class extends
new do delete typeof in instanceof import function
let with var const export debugger
if else for while switch case default try catch finally
function class extends implements new do delete typeof in instanceof
let with var const import export debugger
]>

# The list of keywords that are reserved by JavaScript, but not used.
# We throw a syntax error for these to avoid runtime errors.
KEYWORDS_UNUSED =
<[ enum implements interface package private protected public static yield ]>
<[ enum interface package private protected public static yield ]>

KEYWORDS = KEYWORDS_SHARED.concat KEYWORDS_UNUSED

Expand Down
50 changes: 42 additions & 8 deletions test/oo.co
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,48 @@ class A extends NameEater
eq 'A,B' ''+NameEater.subnames


# Line folding around `extends`
class Inject
extends Object
class Reject extends
Object
ok true


#### `implements`
Mover =
x: 0, y: 0
moveTo: (@x, @y) -> this
moveBy: (dx, dy) -> @x += dx; @y += dy; this

Magnitude =
lt : -> ...
gt : -> it.lt this
lte : -> @lt it or @eq it
gte : -> @gt it or @eq it
eq : -> not @neq it
neq : -> @lt it or @gt it

Measurable =
lt: -> @measure! < it.measure!

class Point implements Mover
isAt: -> @x is it.x and @y is it.y

class Rect extends Point implements Magnitude, Measurable
(@w, @h) ->
measure: -> @w * @h

r0 = new Rect 2 3
r1 = new Rect 5 7
r0.moveTo 1, 1
r1.moveBy 1, 1
ok r0.isAt r1
ok r0.neq r1
ok r1.gte r0
ok r0.eq new Rect 1 6


### Clone
bird = {+wing, fly: -> @wing}
wingless = {-wing}
Expand All @@ -261,11 +303,3 @@ ok not donaldo.fly()

ok ^new Number instanceof Number
eq (^new Number)constructor, Number


# Line folding around `extends`
class Inject
extends Object
class Reject extends
Object
ok true

0 comments on commit 1b3c163

Please sign in to comment.