jam0001/hope at main · langjam/jam0001 · GitHub
source link: https://github.com/langjam/jam0001/tree/main/hope
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
PlsExplain (aka jamlang0001)
A small dynamically typed programming language with first-class comments, where every value is explained by a comment.
Running the Interpreter
Dependencies
The interpreter depends on python3 and lark. Lark can be installed with pip install lark
.
Invoke the interpreter without command line arguments to start the interactive mode
$ ./pls_explain.py
>>> print("hello world")
hello world /*the string "hello world"*/
>>>
To exit press Ctrl-D
.
Running a Scripts
To execute a script written in PlsExplain, pass it as the first command line argument.
$ ./pls_explain.py examples/hello_world.pe
Hello World /*the string "Hello World"*/
First-Class Comments
Comments are first-class values in PlsExplain. This means that they are expressions, can be stored in variables, passed as function arguments and be returned by functions.
>>> let comment = /* This is a comment */;
>>> print(comment)
/* This is a comment */ /* a comment */
>>> print(/*another comment*/)
/*another comment*/ /* a comment */
At a first glance comments might seem to be equivalent to strings. The difference is that comments can be used to explain something. In PlsExplain all values have an associated comment that explains the value. To explain a value with a comment, simply write it next to the expression. When called with a single argument, print
shows the associated comment.
>>> let x = 40 + 2 /* the number fourtytwo */;
>>> print(x)
42 /* the number fourtytwo */
Explaining comments don't have to be comment-literals:
>>> let comment = /* this is a comment */
>>> let x = 42 comment
>>> print(x)
42 /* this is a comment */
Trying to explain a value with something that is not a comment obviously results in a type error.
>>> 42 "this is not a comment"
Backtrace (most recent call last):
line 1:
42 "this is not a comment"
^~~~~~~~~~~~~~~~~~~~~~~~~~
type error: type JlString can not be used to explain values
>>> let s = "not a comment either"
If you see this error, it often means that you have forgotten to separate two expressions with an semicolon.
Auto-generated Comments
If a value is not explained by an explicit comment, the interpreter automagically generates a helpful comment.
>>> let x = 4
>>> print(x)
4.0 /* the number 4.0 */
>>> let y = x + 10
>>> print(y)
14.0 /* the sum of the number 4.0 and the number 10.0 */
The explain operator
The comment explaining a value can be retrieved with the ?
operator.
>>> print(x?)
/* the number 4.0 */
Manipulating Comments
The auto-generated comment can sometimes be a little bit verbose:
let fact = fn(n) {
if (n == 0) {
1
} else {
fact(n - 1) * n;
}
};
print(fact(4));
This program prints:
24.0 /*the product of the product of the product of the product
of the number 1.0 and the difference of the difference of
the difference of the number 4.0 and the number 1.0 and the
number 1.0 and the number 1.0 and the difference of the
difference of the number 4.0 and the number 1.0 and the number
1.0 and the difference of the number 4.0 and the number 1.0
and the number 4.0*/
Since comments are first-class values we can manipulate them on the fly. This allows us to generate even more helpful comments.
let fact = fn(n) {
if (n == 0) {
1
} else {
/* lets generate a helpful comment for the return value */;
/* (Comments can be concatenated with +) */
let comment = /* the factorial of */ + n?;
/* explain the return value with the generated comment */
(fact(n - 1) * n) comment;
}
};
let h = 4 /*the number of hours i've slept*/;
print(fact(h));
The output of this program is more concise:
24.0 /* the factorial of the number of hours i've slept*/
Meta-Comments and Meta-Meta-Comments and ...
Since comments are first-class values, comments are also explained by comments. Obviously comments explaining a comment are also explained by comments which in turn are explained by comments and so on.
>>> let x = 42 /* comment */ /* meta-comment */ /* meta-meta-comment */
>>> print(x)
42 /* comment */
>>> print(x?)
/* comment */ /* meta-comment */
>>> print(x??)
/* meta-comment */ /* meta-meta-comment */
>>> print(x???)
/* meta-meta-comment */ /*a comment*/ <-- autogenerated meta-meta-meta-comment
>>> print(x????)
/*a comment*/ /*a comment*/
...
Datatypes
Type DescriptionComment
the most important type
String
unicode strings
Number
floating point numbers
Bool
True
or False
Unit
only the value ()
List
Lists of values
Lists
Currently there is no special syntax for lists, instead the builtin functions list
,append
,put
and get
have to be used to create and manipulate Lists.
>>> let l = list(1, 2, 3)
>>> print(l)
[1, 2, 3] /*a list of the number 1 and the number 2 and the number 3*/
>>> append(l, "world")
>>> print(l)
[1, 2, 3, world] /*a list of the number 1 and the number 2 and the number 3 and the string "world"*/
>>> print(get(l, 2))
3 /*the number 3*/
>>> put(l, 0, "hallo")
>>> print(l)
[hallo, 2, 3, world] /*a list of the string "hallo" and the number 2 and the number 3 and the string "world"*/
Syntax
The Syntax is Expression based.
Literals
Type ExamplesComment
/* this is a comment */
String
"hello"
"with\n escape \" chars"
Number
1
, -1.0
, 42.5
Bool
True
, False
Unit
()
Grouping
(a + b) * c
Blocks
{ print("hello"); print("world") }
Multiple expressions can be grouped with curly braces. Expressions are separated with semicolons. The semicolon after the last Expression is optional. Blocks evaluate to the value of their last expression.
Functions
Definition
let f = fn (arg) {
print(arg);
};
Functions can be defined with the keyword fn
followed by a parenthesized list of parameters and the function body. The braces are optional, when the body is a single expression. All functions are anonymous and first-class.
Calling a function
print("hello")
Nothing special here.
Variables
Declaration
let x = 42
Variables are declared with the keyword let
and must be initialized. Variables are lexicaly scoped. Declarations evaluate to the assigned value.
Assignment
x = 100
Assignments evaluate to the assigned value.
Unary Expressions
-a
!b
Nothing unusual.
Binary Expressions
a + b
Operators ordered by decreasing precedence:
Operators Examples?
x?
*
, -
, %
x * y
, x % 5
+
, -
x + y
==
, <
, >
x < y
&
x & y
`
`
The only unusual operator is the explain operator (?
). See First Class Comments for more details.
The logic operators &
and |
are not short circuiting.
Control Flow Expressions
if (condition) { "true" } else { "false" }
Parenthesis around the condition are mandatory. Braces around single expressions and the else
branch are optional. If expressions evaluate to the value of the taken branch.
While
while (condition) { do_something() }
Parenthesis around the condition are mandatory. The Braces cant be omitted, if the body is a single expression. While loops evaluate to the value of the loop body during the last iteration.
Builtin Functions
Function Descriptionprint(args...)
Print any number of values. When called with a single argument, the arguments comment is printed as well
input()
Read single line and return it as a string.
str(value)
Convert value to string.
cmnt(value)
Convert value to comment.
num(value)
Convert string to number. Returns ()
if the conversion fails.
list(args...)
Create list containing the arguments.
append(list, value)
Append value to list
put(list, index, value)
Put value into list
get(list, index)
Get value out of list
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK