Something went wrong. Try again.
A prose-themed programming language optimized for minimizing symbols.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241/** * Copyright (c) 2022 Rithvik Arun, Joseph Hale, Jacob Hreshchyshyn, Jacob Janes, Sai Nishanth Vaka * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */
/** * Purpose: Interpreter for Codeable code. * Date: 29 Apr 2022 * Version: 0.1.0 */
% :- use_rendering(svgtree). % Only works in SWISH.swi-prolog.org
/** * codeable_version(-Major,-Minor,-Patch) is det. */codeable_version(0,0,1).
/** * Token Parser */numeric(N) --> [N], {number(N)}.
identifier(I) --> [I], {atom(I)}.
word([W]) --> identifier(W).word([W1 | W2]) --> [W1], word(W2), { atom(W1), W1 \= <, W1 \= > }.strings(str(S)) --> [<], word(W), [>], { atomic_list_concat(W, ' ', S) }.
comment(fyi(S)) --> [fyi], strings(S).
factor(factor_numeric(F)) --> numeric(F).factor(factor_identifier(F)) --> identifier(F).factor(factor_expression(F)) --> ['('], expr(F), [')'].
sub_term(term_factor(T)) --> factor(T).sub_term(term_exponent(F1, F2)) --> factor(F1), [raised_to], factor(F2).
term(T) --> sub_term(T).term(term_times(T1, T2)) --> factor(T1), [times], term(T2).term(term_divide(T1, T2)) --> factor(T1), [divided_by], term(T2).
expr(expr_term(E)) --> term(E).expr(expr_plus(E1, E2)) --> term(E1), [plus], expr(E2).expr(expr_minus(E1, E2)) --> term(E1), [minus], expr(E2).
boolean(true) --> [true].boolean(false) --> [false].boolean(not(B)) --> [not], boolean(B).boolean(equals(E1, E2)) --> expr(E1), [equals], expr(E2).boolean(is_greater_than(E1, E2)) --> expr(E1), [is_greater_than], expr(E2).boolean(is_less_than(E1, E2)) --> expr(E1), [is_less_than], expr(E2).
assignment(assign(I, E)) --> identifier(I), [stores], expr(E).assignment(assign(I, E)) --> identifier(I), [stores], strings(E).assignment(assign(I, E)) --> identifier(I), [stores], selection_inline(E).
selection(if(B, C, fyi(no_op))) --> [if], boolean(B), command(C), [move_on].selection(if(B, C1, C2)) --> [if], boolean(B), command(C1), [otherwise], command(C2), [move_on].selection_inline(ternary(B, T, F)) --> expr(T), [if], boolean(B), [otherwise], expr(F).
loop(for(I, Start, Stop, Step, C)) --> [for], identifier(I), [from], expr(Start), [to], expr(Stop), [by], expr(Step), command(C), [repeat].loop(for(I, Start, Stop, expr_term(term_factor(factor_numeric(1))), C)) --> [for], identifier(I), [from], expr(Start), [to], expr(Stop), command(C), [repeat].
loop(while(B, C)) --> [while], boolean(B), command(C), [repeat].
show(show_string(S)) --> [show], strings(S).show(show_numeric(D)) --> [show], numeric(D).show(show_identifier(I)) --> [show], identifier(I).
command(cmd(C1, C2)) --> comment(C1), command(C2).command(cmd(C1, C2)) --> assignment(C1), command(C2).command(cmd(C1, C2)) --> loop(C1), command(C2).command(cmd(C1, C2)) --> show(C1), command(C2).command(cmd(C1, C2)) --> selection(C1), command(C2).command(C) --> comment(C).command(C) --> assignment(C).command(C) --> loop(C).command(C) --> show(C).command(C) --> selection(C).
program(prog(P)) --> command(P).
/** * eval(+Node, +EnvIn, -EnvOut, -ValueOut) * * Evaluates the parse tree rooted at Node, with the environment EnvIn, * and returns the environment EnvOut and the value ValueOut. * * The environment is a list of pairs (Identifier, Value) where Identifier * is a string and Value is an integer. * */ eval(prog(P), EnvIn, EnvOut, ValueOut) :- eval(P, EnvIn, EnvOut, ValueOut).
eval(fyi(S), EnvIn, EnvIn, S).
eval(str(S), EnvIn, EnvIn, S).
eval(cmd(C1, C2), EnvIn, EnvOut, ValueOut) :- eval(C1, EnvIn, EnvTemp, _ValueOut), eval(C2, EnvTemp, EnvOut, ValueOut).
eval(assign(I, E), EnvIn, EnvOut, ValueOut) :- eval(E, EnvIn, EnvTemp, ValueOut), update(I, ValueOut, EnvTemp, EnvOut).
eval(if(B, T, _), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, true), eval(T, EnvTemp, EnvOut, ValueOut).eval(if(B, _, F), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, false), eval(F, EnvTemp, EnvOut, ValueOut).eval(ternary(B, T, F), EnvIn, EnvOut, ValueOut) :- eval(if(B, T, F), EnvIn, EnvOut, ValueOut).
eval(while(B, C), EnvIn, EnvOut, ValueOut) :- eval(B, EnvIn, EnvTemp, true), eval(C, EnvTemp, EnvTemp2, _ValueOut), eval(while(B, C), EnvTemp2, EnvOut, ValueOut).eval(while(B, _), EnvIn, EnvOut, _ValueOut) :- eval(B, EnvIn, EnvOut, false).
eval(for(I, Start, Stop, Step, C), EnvIn, EnvOut, ValueOut) :- eval(is_less_than(Start, Stop), EnvIn, EnvTemp, true), eval(Start, EnvTemp, EnvTemp1, ValueStart), update(I, ValueStart, EnvTemp1, EnvTemp2), eval(C, EnvTemp2, EnvTemp3, _ValueOut), eval(Step, EnvTemp3, EnvTemp4, ValueStep), NextStart is ValueStart + ValueStep, eval(for(I, expr_term(term_factor(factor_numeric(NextStart))), Stop, Step, C), EnvTemp4, EnvOut, ValueOut).eval(for(I, Start, Stop, _, _), EnvIn, EnvOut, _ValueOut) :- eval(Start, EnvIn, EnvTemp, ValueStart), update(I, ValueStart, EnvTemp, EnvTemp2), eval(is_less_than(Start, Stop), EnvTemp2, EnvOut, false).
eval(expr_plus(Term, Expression), EnvIn, EnvOut, ValueOut) :- eval(Term, EnvIn, EnvTemp, ValTerm), eval(Expression, EnvTemp, EnvOut, ValExpr), ValueOut is ValTerm + ValExpr.eval(expr_minus(Term, Expression), EnvIn, EnvOut, ValueOut) :- eval(Term, EnvIn, EnvTemp, ValTerm), eval(Expression, EnvTemp, EnvOut, ValExpr), ValueOut is ValTerm + (0 - ValExpr).eval(expr_term(T), EnvIn, EnvOut, ValueOut) :- eval(T, EnvIn, EnvOut, ValueOut).eval(expr_assign(A), EnvIn, EnvOut, ValueOut) :- eval(A, EnvIn, EnvOut, ValueOut).
eval(term_exponent(Factor1, Factor2), EnvIn, Env2Out, ValueOut) :- eval(Factor1, EnvIn, Env1Out, Val1Out), eval(Factor2, Env1Out, Env2Out, Val2Out), ValueOut is Val1Out ** Val2Out.eval(term_times(Factor, Term), EnvIn, Env2Out, ValueOut) :- eval(Factor, EnvIn, Env1Out, Val1Out), eval(Term, Env1Out, Env2Out, Val2Out), ValueOut is Val1Out * Val2Out.eval(term_divide(Factor, Term), EnvIn, Env2Out, ValueOut) :- eval(Factor, EnvIn, Env1Out, Val1Out), eval(Term, Env1Out, Env2Out, Val2Out), ValueOut is Val1Out * (1 / Val2Out).eval(term_factor(F), EnvIn, EnvOut, ValueOut) :- eval(F, EnvIn, EnvOut, ValueOut).
eval(factor_numeric(D), EnvIn, EnvIn, D).eval(factor_identifier(I), EnvIn, EnvIn, Value) :- lookup(I, EnvIn, Value).eval(factor_expression(E), EnvIn, EnvOut, Value) :- eval(E, EnvIn, EnvOut, Value).
eval(true, EnvIn, EnvIn, true).eval(false, EnvIn, EnvIn, false).eval(not(B), EnvIn, EnvOut, false) :- eval(B, EnvIn, EnvOut, true).eval(not(B), EnvIn, EnvOut, true) :- eval(B, EnvIn, EnvOut, false).eval(equals(E1, E2), EnvIn, EnvOut, true) :- eval(E1, EnvIn, EnvTemp, ValueOut), eval(E2, EnvTemp, EnvOut, ValueOut).eval(equals(E1, E2), EnvIn, EnvOut, false) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 =\= ValueOut2.eval(is_less_than(E1, E2), EnvIn, EnvOut, true) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 < ValueOut2.eval(is_less_than(E1, E2), EnvIn, EnvOut, false) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 >= ValueOut2.eval(is_greater_than(E1, E2), EnvIn, EnvOut, true) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 > ValueOut2.eval(is_greater_than(E1, E2), EnvIn, EnvOut, false) :- eval(E1, EnvIn, EnvTemp, ValueOut1), eval(E2, EnvTemp, EnvOut, ValueOut2), ValueOut1 =< ValueOut2.
eval(show_char(C), EnvIn, EnvIn, _ValueOut) :-write([output, C]).eval(show_string(str(S)), EnvIn, EnvIn, _ValueOut) :- write([output, S]).eval(show_numeric(D), EnvIn, EnvIn, _ValueOut) :- write([output, D]).eval(show_identifier(I), EnvIn, EnvIn, _ValueOut) :- lookup(I, EnvIn, Value), write([output, Value]).
/** * lookup(+Identifier, +Env, -Value) * * Looks up the Value of Identifier in Env. */lookup(Identifier, [(Identifier, Value) | _], Value).lookup(Identifier, [(OtherIdentifier, _) | RemainingEnvironment], Value) :- Identifier \= OtherIdentifier, lookup(Identifier, RemainingEnvironment, Value).
/** * update(+Identifier, +Value, +EnvIn, -EnvOut) * * Updates the binding of Identifier in EnvIn to Value and returns EnvOut. */update(Identifier, Value, [], [(Identifier, Value)]).update( Identifier, Value, [(Identifier, _) | RemainingEnvironment], [(Identifier, Value) | RemainingEnvironment]).update( Identifier, Value, [(OtherIdentifier, OtherValue) | RemainingEnvironment], [(OtherIdentifier, OtherValue) | NewEnvironment]) :- Identifier \= OtherIdentifier, update(Identifier, Value, RemainingEnvironment, NewEnvironment).