September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -1,3 +0,0 @@
|
|||
module rosetta "1.0.0" {
|
||||
import ceylon.collection "1.2.1";
|
||||
}
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
import ceylon.collection {
|
||||
|
||||
ArrayList
|
||||
}
|
||||
|
||||
class Symbol(shared String text) {
|
||||
string => text;
|
||||
}
|
||||
|
||||
abstract class Node() of Leaf | Branch {}
|
||||
class Leaf(shared String|Integer|Float|Symbol data) extends Node() {
|
||||
string => data.string;
|
||||
}
|
||||
class Branch() extends Node() {
|
||||
shared ArrayList<Node> nodes = ArrayList<Node>();
|
||||
string => nodes.string;
|
||||
}
|
||||
|
||||
shared void run() {
|
||||
|
||||
alias Token => String|Character|Integer|Float|Symbol;
|
||||
|
||||
{Token*} tokenize(String input) {
|
||||
|
||||
class Mode {
|
||||
shared new neutral {}
|
||||
shared new symbol {}
|
||||
shared new quoted {}
|
||||
shared new integer {}
|
||||
shared new float {}
|
||||
shared new escape {}
|
||||
}
|
||||
|
||||
value tokens = ArrayList<Token>();
|
||||
variable value mode = Mode.neutral;
|
||||
value currentToken = StringBuilder();
|
||||
|
||||
void completeToken() {
|
||||
value string = currentToken.string;
|
||||
if(mode == Mode.symbol) {
|
||||
tokens.add(Symbol(string));
|
||||
}
|
||||
if(mode == Mode.quoted) {
|
||||
tokens.add(string);
|
||||
}
|
||||
if(mode == Mode.integer) {
|
||||
assert(exists int = parseInteger(string));
|
||||
tokens.add(int);
|
||||
}
|
||||
if(mode == Mode.float) {
|
||||
assert(exists float = parseFloat(string));
|
||||
tokens.add(float);
|
||||
}
|
||||
mode = Mode.neutral;
|
||||
currentToken.clear();
|
||||
}
|
||||
|
||||
for(char in input) {
|
||||
switch(char)
|
||||
case('(' | ')') {
|
||||
if(mode != Mode.quoted) {
|
||||
completeToken();
|
||||
tokens.add(char);
|
||||
} else {
|
||||
currentToken.appendCharacter(char);
|
||||
}
|
||||
}
|
||||
case('\"') {
|
||||
if(mode == Mode.escape) {
|
||||
currentToken.appendCharacter(char);
|
||||
mode = Mode.quoted;
|
||||
} else if(mode != Mode.quoted) {
|
||||
mode = Mode.quoted;
|
||||
} else if(mode == Mode.quoted) {
|
||||
completeToken();
|
||||
}
|
||||
}
|
||||
case('\\') {
|
||||
if(mode == Mode.quoted) {
|
||||
mode = Mode.escape;
|
||||
} else {
|
||||
currentToken.appendCharacter(char);
|
||||
}
|
||||
}
|
||||
case(' ' | '\n' | '\r') {
|
||||
if(mode != Mode.quoted) {
|
||||
completeToken();
|
||||
} else {
|
||||
currentToken.append(" ");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mode == Mode.neutral) {
|
||||
if(char.digit) {
|
||||
mode = Mode.integer;
|
||||
} else {
|
||||
mode = Mode.symbol;
|
||||
}
|
||||
}
|
||||
if(mode == Mode.integer && (char == '.' || char == ',')) {
|
||||
mode = Mode.float;
|
||||
}
|
||||
currentToken.appendCharacter(char);
|
||||
}
|
||||
}
|
||||
completeToken();
|
||||
return tokens;
|
||||
}
|
||||
|
||||
Node readFromTokens(ArrayList<Token> tokens) {
|
||||
if(exists first = tokens.accept()) {
|
||||
if(first == '(') {
|
||||
value branch = Branch();
|
||||
while(!tokens.empty) {
|
||||
if(exists token = tokens.first) {
|
||||
if(token == ')') {
|
||||
tokens.accept();
|
||||
break;
|
||||
} else {
|
||||
branch.nodes.add(readFromTokens(tokens));
|
||||
}
|
||||
}
|
||||
}
|
||||
return branch;
|
||||
} else {
|
||||
if(is String|Integer|Float|Symbol first) {
|
||||
return Leaf(first);
|
||||
} else {
|
||||
throw Exception("unexpected token ``first``");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Branch();
|
||||
}
|
||||
}
|
||||
|
||||
void prettyPrint(Node node, Integer indentation = 0) {
|
||||
|
||||
void paddedPrint(String s) => print(" ".repeat(indentation) + s);
|
||||
|
||||
if(is Leaf node) {
|
||||
paddedPrint(node.string);
|
||||
} else {
|
||||
paddedPrint("(");
|
||||
for(n in node.nodes) {
|
||||
prettyPrint(n, indentation + 2);
|
||||
}
|
||||
paddedPrint(")");
|
||||
}
|
||||
}
|
||||
|
||||
value tokens = tokenize("""((data "quoted data" 123 4.5)
|
||||
(data (!@# (4.5) "(more" "data)")))""");
|
||||
value tree = readFromTokens(ArrayList {*tokens});
|
||||
prettyPrint(tree);
|
||||
}
|
||||
168
Task/S-Expressions/Ceylon/s-expressions.ceylon
Normal file
168
Task/S-Expressions/Ceylon/s-expressions.ceylon
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
class Symbol(symbol) {
|
||||
shared String symbol;
|
||||
string => symbol;
|
||||
}
|
||||
|
||||
abstract class Token()
|
||||
of DataToken | leftParen | rightParen {}
|
||||
|
||||
abstract class DataToken(data)
|
||||
of StringToken | IntegerToken | FloatToken | SymbolToken
|
||||
extends Token() {
|
||||
|
||||
shared String|Integer|Float|Symbol data;
|
||||
string => data.string;
|
||||
}
|
||||
|
||||
class StringToken(String data) extends DataToken(data) {}
|
||||
class IntegerToken(Integer data) extends DataToken(data) {}
|
||||
class FloatToken(Float data) extends DataToken(data) {}
|
||||
class SymbolToken(Symbol data) extends DataToken(data) {}
|
||||
|
||||
object leftParen extends Token() {
|
||||
string => "(";
|
||||
}
|
||||
object rightParen extends Token() {
|
||||
string => ")";
|
||||
}
|
||||
|
||||
class Tokens(String input) satisfies {Token*} {
|
||||
shared actual Iterator<Token> iterator() => object satisfies Iterator<Token> {
|
||||
|
||||
variable value index = 0;
|
||||
|
||||
shared actual Token|Finished next() {
|
||||
|
||||
while(exists nextChar = input[index], nextChar.whitespace) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if(index >= input.size) {
|
||||
return finished;
|
||||
}
|
||||
|
||||
assert(exists char = input[index]);
|
||||
|
||||
if(char == '(') {
|
||||
index++;
|
||||
return leftParen;
|
||||
}
|
||||
if(char == ')') {
|
||||
index++;
|
||||
return rightParen;
|
||||
}
|
||||
|
||||
if(char == '"') {
|
||||
value builder = StringBuilder();
|
||||
while(exists nextChar = input[++index]) {
|
||||
if(nextChar == '"') {
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
if(nextChar == '\\') {
|
||||
if(exists nextNextChar = input[++index]) {
|
||||
switch(nextNextChar)
|
||||
case('\\') {
|
||||
builder.append("\\");
|
||||
}
|
||||
case('t') {
|
||||
builder.append("\t");
|
||||
}
|
||||
case('n') {
|
||||
builder.append("\n");
|
||||
}
|
||||
case('"') {
|
||||
builder.append("\"");
|
||||
}
|
||||
else {
|
||||
throw Exception("unknown escaped character");
|
||||
}
|
||||
} else {
|
||||
throw Exception("unclosed string");
|
||||
}
|
||||
} else {
|
||||
builder.appendCharacter(nextChar);
|
||||
}
|
||||
}
|
||||
return StringToken(builder.string);
|
||||
}
|
||||
|
||||
value builder = StringBuilder();
|
||||
while(exists nextChar = input[index], !nextChar.whitespace && nextChar != '(' && nextChar != ')') {
|
||||
builder.appendCharacter(nextChar);
|
||||
index++;
|
||||
}
|
||||
value string = builder.string;
|
||||
if(is Integer int = Integer.parse(string)) {
|
||||
return IntegerToken(int);
|
||||
} else if(is Float float = Float.parse(string)) {
|
||||
return FloatToken(float);
|
||||
} else {
|
||||
return SymbolToken(Symbol(string));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
abstract class Node() of Atom | Group {}
|
||||
|
||||
class Atom(data) extends Node() {
|
||||
shared String|Integer|Float|Symbol data;
|
||||
string => data.string;
|
||||
}
|
||||
class Group() extends Node() satisfies {Node*} {
|
||||
shared variable Node[] nodes = [];
|
||||
string => nodes.string;
|
||||
shared actual Iterator<Node> iterator() => nodes.iterator();
|
||||
|
||||
}
|
||||
|
||||
Node buildTree(Tokens tokens) {
|
||||
|
||||
[Group, Integer] recursivelyBuild(Token[] tokens, variable Integer index = 0) {
|
||||
value result = Group();
|
||||
while(exists token = tokens[index]) {
|
||||
switch (token)
|
||||
case (leftParen) {
|
||||
value [newNode, newIndex] = recursivelyBuild(tokens, index + 1);
|
||||
index = newIndex;
|
||||
result.nodes = result.nodes.append([newNode]);
|
||||
}
|
||||
case (rightParen) {
|
||||
return [result, index];
|
||||
}
|
||||
else {
|
||||
result.nodes = result.nodes.append([Atom(token.data)]);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return [result, index];
|
||||
}
|
||||
|
||||
value root = recursivelyBuild(tokens.sequence())[0];
|
||||
return root.first else Group();
|
||||
}
|
||||
|
||||
void prettyPrint(Node node, Integer indentation = 0) {
|
||||
|
||||
void paddedPrint(String s) => print(" ".repeat(indentation) + s);
|
||||
|
||||
if(is Atom node) {
|
||||
paddedPrint(node.string);
|
||||
} else {
|
||||
paddedPrint("(");
|
||||
for(n in node.nodes) {
|
||||
prettyPrint(n, indentation + 2);
|
||||
}
|
||||
paddedPrint(")");
|
||||
}
|
||||
}
|
||||
|
||||
shared void run() {
|
||||
value tokens = Tokens("""((data "quoted data" 123 4.5)
|
||||
(data (!@# (4.5) "(more" "data)")))""");
|
||||
print(tokens);
|
||||
|
||||
value tree = buildTree(tokens);
|
||||
prettyPrint(tree);
|
||||
}
|
||||
|
|
@ -1,64 +1,55 @@
|
|||
/*REXX program parses an S-expression and displays the results. */
|
||||
/*REXX program parses an S-expression and displays the results to the terminal. */
|
||||
input= '((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))'
|
||||
say 'input:'; say input /*display the input data string to term*/
|
||||
say copies('═', length(input)) /*also, display a header fence. */
|
||||
groupO.= /*default value for grouping symbols. */
|
||||
groupO.1 = '{' ; groupC.1 = "}" /*grouping symbols (Open & Close). */
|
||||
groupO.2 = '[' ; groupC.2 = "]" /* " " " " " */
|
||||
groupO.3 = '(' ; groupC.3 = ")" /* " " " " " */
|
||||
say center('input', length(input), "═") /*display the header title to terminal.*/
|
||||
say input /* " " input data " " */
|
||||
say copies('═', length(input) ) /* " " header sep " " */
|
||||
grpO.=; grpO.1 = '{' ; grpC.1 = "}" /*pair of grouping symbol: braces */
|
||||
grpO.2 = '[' ; grpC.2 = "]" /* " " " " brackets */
|
||||
grpO.3 = '(' ; grpC.3 = ")" /* " " " " parentheses */
|
||||
grpO.4 = '«' ; grpC.4 = "»" /* " " " " guillemets */
|
||||
q.=; q.1 = "'" ; q.2 = '"' /*1st and 2nd literal string delimiter.*/
|
||||
# = 0 /*the number of tokens found (so far). */
|
||||
tabs = 10 /*used for the indenting of the levels.*/
|
||||
q.1 = "'" /*literal string delimiter, first. */
|
||||
q.2 = '"' /* " " " second. */
|
||||
numLits = 2 /*the number of kinds of literals. */
|
||||
seps = ',;' /*characters used for separation. */
|
||||
atoms = ' 'seps /*characters used to separate atoms. */
|
||||
atoms = ' 'seps /* " " to separate atoms. */
|
||||
level = 0 /*the current level being processed. */
|
||||
quoted = 0 /*quotation level (when nested). */
|
||||
groupu = /*used to go ↑ an expression level. */
|
||||
groupd = /* " " " ↓ " " " */
|
||||
$.= /*the stem array to hold the tokens. */
|
||||
do n=1 while groupO.n\=='' /*handle the number of grouping symbols*/
|
||||
atoms =atoms || groupO.n || groupC.n
|
||||
groupu=groupu || groupO.n
|
||||
groupd=groupd || groupC.n
|
||||
end /*n*/
|
||||
quoted = 0 /*quotation level (for nested quotes).*/
|
||||
grpU = /*used to go up an expression level.*/
|
||||
grpD = /* " " " down " " " */
|
||||
@.=; do n=1 while grpO.n\==''
|
||||
atoms = atoms || grpO.n || grpC.n /*add Open and Closed groups to ATOMS.*/
|
||||
grpU = grpU || grpO.n /*add Open groups to GRPU, */
|
||||
grpD = grpD || grpC.n /*add Closed groups to GRPD, */
|
||||
end /*n*/ /* [↑] handle a bunch of grouping syms*/
|
||||
literals=
|
||||
do k=1 for numLits
|
||||
literals=literals || q.k
|
||||
end /*k*/
|
||||
!=
|
||||
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ text parsing ▒▒▒▒▒▒▒▒*/
|
||||
do j=1 to length(input); _=substr(input,j,1) /*▒*/
|
||||
/*▒*/
|
||||
if quoted then do; !=! || _ /*▒*/
|
||||
if _==literalStart then quoted=0 /*▒*/
|
||||
iterate /*▒*/
|
||||
end /*▒*/
|
||||
/*▒*/
|
||||
if pos(_,literals)\==0 then do; literalStart=_ /*▒*/
|
||||
!=! || _ /*▒*/
|
||||
quoted=1 /*▒*/
|
||||
iterate /*▒*/
|
||||
end /*▒*/
|
||||
/*▒*/
|
||||
if pos(_,atoms)==0 then do; !=! || _ ; iterate; end /*▒*/
|
||||
else do; call add!; !=_; end /*▒*/
|
||||
/*▒*/
|
||||
if pos(_,literals)==0 then do; if pos(_,groupu)\==0 then level=level+1 /*▒*/
|
||||
call add! /*▒*/
|
||||
if pos(_,groupd)\==0 then level=level-1 /*▒*/
|
||||
if level<0 then say 'oops, mismatched' _ /*▒*/
|
||||
end /*▒*/
|
||||
end /*j*/ /*▒*/
|
||||
/*▒*/
|
||||
call add! /*handle any residual tokens.*/ /*▒*/
|
||||
if level\==0 then say 'oops, mismatched grouping symbol' /*▒*/
|
||||
if quoted then say 'oops, no end of quoted literal' literalStart /*▒*/
|
||||
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒*/
|
||||
do k=1 while q.k\==''; literals=literals || q.k /*add literal delimiters*/
|
||||
end /*k*/
|
||||
!=; literalStart=
|
||||
do j=1 to length(input); $=substr(input, j, 1) /* ◄■■■■■text parsing*/
|
||||
/* ◄■■■■■text parsing*/
|
||||
if quoted then do; !=! || $; if $==literalStart then quoted=0 /* ◄■■■■■text parsing*/
|
||||
iterate /* ◄■■■■■text parsing*/
|
||||
end /* [↑] handle running quoted str.*/ /* ◄■■■■■text parsing*/
|
||||
/* ◄■■■■■text parsing*/
|
||||
if pos($, literals)\==0 then do; literalStart=$; !=! || $; quoted=1 /* ◄■■■■■text parsing*/
|
||||
iterate /* ◄■■■■■text parsing*/
|
||||
end /* [↑] handle start of quoted str.*/ /* ◄■■■■■text parsing*/
|
||||
/* ◄■■■■■text parsing*/
|
||||
if pos($, atoms)==0 then do; !=! || $ ; iterate; end /*is an atom?*/ /* ◄■■■■■text parsing*/
|
||||
else do; call add!; !=$; end /*isn't an atam?*/ /* ◄■■■■■text parsing*/
|
||||
/* ◄■■■■■text parsing*/
|
||||
if pos($, literals)==0 then do; if pos($, grpU)\==0 then level=level + 1 /* ◄■■■■■text parsing*/
|
||||
call add! /* ◄■■■■■text parsing*/
|
||||
if pos($, grpD)\==0 then level=level - 1 /* ◄■■■■■text parsing*/
|
||||
if level<0 then say 'error, mismatched' $ /* ◄■■■■■text parsing*/
|
||||
end /* ◄■■■■■text parsing*/
|
||||
end /*j*/ /* ◄■■■■■text parsing*/
|
||||
/* ◄■■■■■text parsing*/
|
||||
call add! /*process any residual tokens.*/ /* ◄■■■■■text parsing*/
|
||||
if level\==0 then say 'error, mismatched grouping symbol' /* ◄■■■■■text parsing*/
|
||||
if quoted then say 'error, no end of quoted literal' literalStart /* ◄■■■■■text parsing*/
|
||||
|
||||
do m=1 for #; say $.m; end /*m*/ /*display the tokens to the terminal. */
|
||||
do m=1 for #; say @.m; end /*m*/ /*display the tokens to the terminal. */
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
add!: if !\='' then do; #=#+1; $.#=left('', max(0, tabs*(level-1)))!; end; !=
|
||||
return
|
||||
add!: if !='' then return; #=#+1; @.#=left("", max(0, tabs*(level-1)))!; !=; return
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
@/\s*\(\s*/@(coll :vars (e))@(expr e)@/\s*/@(last))@(end)
|
||||
Loading…
Add table
Add a link
Reference in a new issue