Browse Source

Merge pull request #18 from oftn/master

merge OFTN version
pull/21/head
Wesley Kerfoot 10 years ago
parent
commit
93cb81c719
  1. 14
      desugar.js
  2. 6
      example.jl
  3. 176
      parse.js
  4. 2
      pprint.js
  5. 50
      prelude.jl
  6. 28
      representation.js
  7. 2
      tokenize.js

14
desugar.js

@ -47,14 +47,14 @@ function desugarLet(stx) {
return new typ.LetExp(values, desugar(stx.body));
}
function sugarTypeApp(stx) {
function sugarTypeDecl(stx) {
var type;
var expression;
type = stx.p;
expression = desugar(stx.func.p);
expression.linenum = stx.linenum;
expression.charnum = stx.charnum;
return new typ.TypeApp(expression, type);
return new typ.TypeDecl(expression, type);
}
function desugarDefType(stx) {
@ -86,19 +86,19 @@ function desugar(stx) {
case "Application":
if ((stx.func.func !== undefined ) &&
(stx.func.func.ident === "::")) {
/* It's a type application probably (will be verified later)
* In this case we actually *add* syntax here to differentiate type applications
* from normal applications
/* It's a type declaration probably (will be verified later)
* In this case we actually *add* syntax here to differentiate type declarations
* from normal function application
*/
typeExpTest = typ.isTypeExpr(stx.p);
if (typeExpTest.failed !== undefined &&
typeExpTest.failed) {
throw errors.JInternalError(
"Type application error near line " + stx.linenum + " at character #"+stx.charnum +
"Type declaration error near line " + stx.linenum + " at character #"+stx.charnum +
"\n"+typeExpTest.stx.exprType+" (" + typeExpTest.stx.val + ") found where a type operator or type application was expected");
}
return sugarTypeApp(stx);
return sugarTypeDecl(stx);
}
if ((stx.func.ident === "-" ||

6
example.jl

@ -1,6 +1,9 @@
defop 2 Left (a ++ b)
(a - b)
def foo# 3
deftype Foo (A -> B)
;; here is a comment
@ -46,7 +49,7 @@ def (testUnary n)
def (foo bar)
let {
lol = [1,
lol = [1,
(lambda qwerty blah ->
[qerty, blah,
(lambda whatever -> whatever)])]
@ -79,6 +82,7 @@ def r def
def main
let {
(f a) -> a
unary = (print (testUnary 6))
splitted = def {
xs = (fst (splitxs [12,3,4,56]))

176
parse.js

@ -192,8 +192,8 @@ function parseDefFunction(tokens, linenum, charnum) {
var body;
if (fname.exprType !== "Name") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(linenum,
charnum,
"Expected an identifier in function definition");
}
if (fst(tokens)[0] === "right_paren") {
@ -204,17 +204,17 @@ function parseDefFunction(tokens, linenum, charnum) {
validName,
validFormPar,
tokens,
fst(tokens)[2],
fst(tokens)[3]);
charnum,
linenum);
}
if (!tokens || (fst(tokens)[0]) !== "right_paren") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(linenum,
charnum,
"Formal parameters must be followed by )");
}
tokens.pop();
body = parse(tokens);
result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, linenum, charnum);
result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, body.linenum, body.charnum);
return result;
}
@ -235,32 +235,32 @@ function parseLetForm(tokens, linenum, charnum) {
validLet,
letEnd,
tokens,
linenum,
charnum);
charnum,
linenum);
if (fst(tokens) && fst(tokens)[0] !== "right_brace") {
throw error.JSyntaxError(fst(tokens)[2],
fst(tokens)[3],
"let/def form must have a closing }");
}
if (!fst(tokens)) {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(_.last(pairs).linenum,
_.last(pairs).charnum,
"Unexpected end of source");
}
tokens.pop();
if (tokens.length <= 0) {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(_.last(pairs).linenum,
_.last(pairs).charnum,
"let/def form must have a body");
}
body = parse(tokens);
if (body.exprType === "Definition" ||
body.exprType === "FunctionDefinition") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(body.linenum,
body.charnum,
"Body of a let/def expression cannot be a definition");
}
result = addSrcPos(new typ.LetExp(pairs, body), tokens, linenum, charnum);
result = addSrcPos(new typ.LetExp(pairs, body), tokens, body.linenum, body.charnum);
return result;
}
@ -284,12 +284,12 @@ function parseLetFunction(tokens, linenum, charnum) {
validName,
validFormPar,
tokens,
fst(tokens)[2],
fst(tokens)[3]);
charnum,
linenum);
}
if ((fst(tokens)[0]) !== "right_paren") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(linenum,
charnum,
"Formal parameters must be followed by )");
}
tokens.pop();
@ -300,7 +300,7 @@ function parseLetFunction(tokens, linenum, charnum) {
}
tokens.pop();
body = parse(tokens);
result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, linenum, charnum);
result = addSrcPos(new typ.DefFunc(fname, parameters, body), tokens, body.linenum, body.charnum);
return result;
}
@ -310,46 +310,49 @@ function parseLetBinding(tokens, linenum, charnum) {
var bound;
if (name.exprType != "Name") {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(name.linenum,
name.charnum,
"Expected an identifier in let/def binding");
}
if (!fst(tokens) || fst(tokens)[1] !== "=") {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(name.linenum,
name.charnum,
"An identifier in a let/def binding must be followed by ``=''");
}
tokens.pop();
if (!notFollowedBy(tokens,
["comma", "arrow", "right_brace", "right_square"],
linenum,
charnum)) {
throw error.JSyntaxError(linenum,
charnum,
name.linenum,
name.charnum)) {
throw error.JSyntaxError(name.linenum,
name.charnum,
"The binding of " + identifier.val + " must not be followed by " + fst(tokens)[0]);
}
bound = parse(tokens);
if (bound.exprType === "Definition" ||
bound.exprType === "FunctionDefinition") {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(bound.linenum,
bound.charnum,
"A definition cannot be the value of a binding");
}
result = addSrcPos(new typ.Def(name, bound), tokens, linenum, charnum);
result = addSrcPos(new typ.Def(name, bound), tokens, bound.linenum, bound.charnum);
return result;
}
function parseLetItem(tokens) {
var linenum = fst(tokens)[3];
var charnum = fst(tokens)[2];
if (fst(tokens) && fst(tokens)[0] === "left_paren") {
tokens.pop();
return parseLetFunction(tokens,
fst(tokens)[3],
fst(tokens)[2]);
linenum,
charnum);
}
else {
return parseLetBinding(tokens,
fst(tokens)[3],
fst(tokens)[2]);
linenum,
charnum);
}
}
@ -365,14 +368,14 @@ function parseDataType(tokens, linenum, charnum) {
"Expected a type operator in data type definition");
}
parameters = parseMany(parse,
validName,
validFormPar,
tokens,
charnum,
linenum);
validName,
validFormPar,
tokens,
charnum,
linenum);
if (!tokens || (fst(tokens)[0]) !== "right_paren") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(_.last(parameters).linenum,
_.last(parameters).charnum,
"Data type parameters must be followed by )");
}
tokens.pop();
@ -414,8 +417,8 @@ function parseDefType(tokens, linenum, charnum) {
else {
lhs = parse(tokens, linenum, charnum);
if (!tokens) {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(lhs.linenum,
lhs.charnum,
"Unexpected end of source");
}
if (lhs.exprType !== "TypeOperator") {
@ -431,7 +434,7 @@ function parseDefType(tokens, linenum, charnum) {
rhs.charnum,
"was expecting an application or type operator on the right-hand side of a type definition");
}
result = addSrcPos(new typ.DefType(lhs, rhs), tokens, linenum, charnum);
result = addSrcPos(new typ.DefType(lhs, rhs), tokens, rhs.linenum, rhs.charnum);
return result;
}
}
@ -475,24 +478,22 @@ function parseDef(tokens, linenum, charnum) {
else {
identifier = parse(tokens);
if (!fst(tokens))
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(identifier.linenum,
identifier.charnum,
"Unexpected end of source");
linenum = fst(tokens)[3];
charnum = fst(tokens)[2];
if (!notFollowedBy(tokens,
["comma", "arrow", "right_brace", "right_square"],
linenum,
charnum)) {
throw error.JSyntaxError(linenum,
charnum,
identifier.linenum,
identifier.charnum)) {
throw error.JSyntaxError(identifier.linenum,
identifier.charnum,
"def " + identifier.val + " must not be followed by " + fst(tokens)[0]);
}
bound = parse(tokens);
if (bound.exprType === "Definition" ||
bound.exprType === "FunctionDefinition") {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(bound.linenum,
bound.charnum,
"A definition cannot be the value of a binding");
}
result = addSrcPos(new typ.Def(identifier, bound), tokens, bound.linenum, bound.charnum);
@ -503,6 +504,7 @@ function parseDef(tokens, linenum, charnum) {
function parseDefOp(tokens, linenum, charnum) {
var result;
var names;
var pattern;
if (fst(tokens)[0] !== "integer" ||
fst(tokens)[1] < 1) {
@ -532,7 +534,7 @@ function parseDefOp(tokens, linenum, charnum) {
charnum,
"defop must be surrounded by exactly 3 identifiers");
}
var pattern = tokens.slice(tokens.length-3,
pattern = tokens.slice(tokens.length-3,
tokens.length);
tokens.pop(); tokens.pop(); tokens.pop();
if (fst(tokens)[0] !== "right_paren") {
@ -554,17 +556,19 @@ function parseDefOp(tokens, linenum, charnum) {
names.slice(1,3),
parse(tokens)),
tokens,
linenum,
charnum);
_.last(names).linenum,
_.last(names).charnum);
return result;
}
function parseIf(tokens) {
var linenum = fst(tokens)[3];
var charnum = fst(tokens)[2];
function parseIf(tokens, linenum, charnum) {
var result;
var ifC;
var thenC;
var elseC;
if (!notFollowedBy(tokens,
["def","comma","lambda"],
linenum,
@ -574,32 +578,32 @@ function parseIf(tokens) {
"``if'' cannot be followed by "+fst(tokens)[0]) ;
}
else {
var ifC = parse(tokens);
ifC = parse(tokens);
if (!fst(tokens) || fst(tokens)[0] !== "thenexp") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(ifC.linenum,
ifC.charnum,
"if ``exp'' must be folowed by ``then'' exp, not "+snd(tokens)[0]);
}
else {
tokens.pop();
var thenC = parse(tokens);
thenC = parse(tokens);
if (fst(tokens) && fst(tokens)[0] === "elsexp") {
tokens.pop();
if (_.size(tokens) < 1) {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(thenC.linenum,
thenC.charnum,
"Unexpected end of source");
}
else {
var elseC = parse(tokens);
elseC = parse(tokens);
result = addSrcPos(new typ.If(ifC, thenC, elseC), tokens, elseC.linenum, elseC.charnum);
return result;
}
}
else {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(thenC.linenum,
thenC.charnum,
"If expression must include an else variant");
}
}
@ -613,9 +617,7 @@ function validFormPar(tok) {
tok[1] !== "->";
}
function parseLambda(tokens) {
var linenum = fst(tokens)[2];
var charnum = fst(tokens)[3];
function parseLambda(tokens, linenum, charnum) {
var result;
var parameters = parseMany(parse,
validName,
@ -624,8 +626,8 @@ function parseLambda(tokens) {
charnum,
linenum);
if (fst(tokens)[1] !== "->") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(_.last(parameters).linenum,
_.last(parameters).charnum,
"arrow must follow parameters in lambda, not "+fst(tokens)[0]);
}
tokens.pop();
@ -643,20 +645,22 @@ function computeApp(tokens, charnum, linenum) {
var lhs = parse(tokens);
var next;
var result;
var parameters;
if (fst(tokens)) {
next = fst(tokens);
}
else {
throw error.JSyntaxError(linenum,
charnum,
throw error.JSyntaxError(lhs.linenum,
lhs.charnum,
"Unexpected end of source");
}
if (typ.OPInfo[next[1]]) {
/* it's an infix expression */
result = parseInfix(tokens, 1, lhs, linenum, charnum);
result = parseInfix(tokens, 1, lhs, lhs.linenum, lhs.charnum);
if (!fst(tokens) || fst(tokens)[0] !== "right_paren") {
throw error.JSyntaxError(fst(tokens)[3],
fst(tokens)[2],
throw error.JSyntaxError(lhs.linenum,
lhs.charnum,
"Mismatched parentheses or missing parenthesis on right-hand side");
}
else {
@ -666,7 +670,6 @@ function computeApp(tokens, charnum, linenum) {
}
else {
/* it's a prefix application */
var parameters;
if (fst(tokens)[0] !== "right_paren") {
parameters = parseMany(parse,
validArgTypes,
@ -744,7 +747,7 @@ function parse(tokens) {
return parseList(tokens, linenum, charnum);
}
else if (toktype === "lambda") {
return parseLambda(tokens);
return parseLambda(tokens, linenum, charnum);
}
else if (toktype === "integer") {
result = addSrcPos(new typ.IntT(token), tokens, linenum, charnum);
@ -777,12 +780,12 @@ function parse(tokens) {
return parseDefOp(tokens, linenum, charnum);
}
else if (toktype === "ifexp") {
return parseIf(tokens);
return parseIf(tokens, linenum, charnum);
}
else if (toktype === "left_paren") {
if (fst(tokens)[0] === "lambda") {
tokens.pop();
var parsed = parseLambda(tokens);
var parsed = parseLambda(tokens, linenum, charnum);
tokens.pop();
return parsed;
}
@ -801,8 +804,7 @@ function parseFull(tokenized) {
var ast = [];
try {
while (tokenized.length > 0) {
var parsed = desugarer.desugar(parse(tokenized));
ast.push(parsed);
ast.push(desugarer.desugar(parse(tokenized)));
}
return ast;
} catch (e) {

2
pprint.js

@ -94,7 +94,7 @@ function pprint(expr) {
else if (expr.exprType === "TypeVar") {
return "("+expr.name+")";
}
else if (expr.exprType === "TypeApplication") {
else if (expr.exprType === "TypeDeclaration") {
return "( " + pprint(expr.expression) + " :: " + pprint(expr.type) + " )";
}
}

50
prelude.jl

@ -2,8 +2,56 @@
;; It is sort of special in that it doesn't care whether there are any associated definitions
;; just that there are type definitions for that particular binding's name
deftype String (List Char)
;; Type definitions
deftype String (A300 Char)
deftype Int Intrinsic
deftype Float Intrinsic
deftype Char Intrinsic
deftype Byte Intrinsic
deftype Void Intrinsic
deftype IO Intrinsic
deftype (List a)
(Empty |
(Cons a (List a)))
deftype (Maybe a)
(Nothing |
(Just a))
deftype (Either a b)
((Left a) |
(Right b))
;; List functions
(: :: (a -> (List a) -> (List a)))
(map :: ((a -> b) -> (List a) -> (List b)))
(head :: ((List a) -> a))
(tail :: ((List a) -> (List a)))
(!! :: (Int -> (List a) -> a))
(take :: (Int -> (List a) -> (Maybe (List a))))
(drop :: (Int -> (List a) -> (Maybe (List a))))
;; Optional functions
(maybe :: (b -> (a -> b) -> (Maybe a) -> b))
(either :: ((b -> c) -> (b -> c) -> (Either a b) -> c))
;; I/O functions
(print :: (String -> (IO Void)))

28
representation.js

@ -37,17 +37,17 @@ function isIrregularTypeOp(x) {
return (x === "->");
}
function flattenTypeApp(stx) {
function flattenTypeDecl(stx) {
if (isTypeExpr(stx)) {
return true;
}
if (stx.exprType === "Application") {
/* it might be a type application so recursively check it */
if (stx.p !== undefined) {
return _.flatten([flattenTypeApp(stx.p), flattenTypeApp(stx.func)]);
return _.flatten([flattenTypeDecl(stx.p), flattenTypeDecl(stx.func)]);
}
else {
return _.flatten([flattenTypeApp(stx.func)]);
return _.flatten([flattenTypeDecl(stx.func)]);
}
}
if (stx.exprType === "Name") {
@ -66,7 +66,7 @@ function flattenTypeApp(stx) {
function isTypeExprRec(stx) {
var flattened = flattenTypeApp(stx);
var flattened = flattenTypeDecl(stx);
for(var i = 0; i < flattened.length; i++) {
if (flattened[i].failed !== undefined &&
flattened[i].failed) {
@ -266,36 +266,36 @@ function isTypeExpr(expr) {
}
return ((expr.exprType === "TypeOperator") ||
(expr.exprType === "TypeVar") ||
(expr.exprType === "TypeApplication"));
(expr.exprType === "TypeDeclaration"));
}
function TypeApp(expression, type) {
function TypeDecl(expression, type) {
if (isTypeExprRec(expression) &&
expression.exprType !== "Name") {
throw errors.JSyntaxError(
expression.linenum,
expression.charnum,
"Left-hand-side of type application must not be in the type language"
"Left-hand-side of type declaration must not be in the type language"
);
}
if (!isTypeExprRec(type)) {
if (isTypeExprRec(type).failed) {
throw errors.JInternalError(
"Right-hand-side of type application must be a type expression"
"Right-hand-side of type declaration must be a type expression"
);
}
this.expression = expression;
this.type = type;
this.exprType = "TypeApplication";
this.exprType = "TypeDeclaration";
return this;
}
TypeApp.prototype = TypeExpression;
TypeDecl.prototype = TypeExpression;
function DefType(lhs, rhs) {
/* Both rhs and lhs are expected
* to be fully desugared already
*/
if (!isTypeExprRec(rhs) ||
if (isTypeExprRec(rhs).failed ||
!isTypeExpr(lhs)) {
throw errors.JSyntaxError(
rhs.linenum,
@ -331,7 +331,7 @@ function DataType(name, params, type) {
"which is a type operator");
}
_.each(params, checkName);
if (!isTypeExprRec(type)) {
if (isTypeExprRec(type).failed) {
throw errors.JSyntaxError(
type.linenum,
type.charnum,
@ -416,7 +416,7 @@ module.exports =
gensym : gensym,
TypeVar : TypeVar,
TypeOp : TypeOp,
TypeApp: TypeApp,
TypeDecl : TypeDecl,
Closure : Closure,
isTypeExpr : isTypeExprRec,
DefType : DefType,

2
tokenize.js

@ -310,7 +310,7 @@ function tokenize(tokstream, matchop) {
if (deftype) {
tokens.push(["deftype", "deftype", charnum, linenum]);
tokstream = tokstream.substr(7);
break
break;
}
var def = peek(tokstream, "def", "def");
if (def) {

Loading…
Cancel
Save