Some more info, preparations for float

parent b746e877
......@@ -11,6 +11,10 @@ For the better or the worse, PRAKDA has a unique syntax which allows to create f
The ~make~ keyword allows the creation or definition of a function. Its name, beginning with a character and composed of characters or numbers, follows. The colon (~:~) marks the beginning of the arguments. There can be either no arguments, marked with ~()~, or several of them, marked as shown below. The right arrow ~->~ indicates the return type of the function, whereas the left arrow ~<-~ indicates the body of the function. It can either be a one-liner with only one instruction, or it can be a block of instructions surrounded by the keywords ~begin~ and ~end~. Here's an example with a naive Fibonacci function:
#+BEGIN_SRC text -n
$$$
Declaration of the function `fib` which takes either a function returning a
literal int or a literal int itself as its argument, and returns a literal int
$$$
make fib: $ declaration of the `fib` function
(i: () -> int) $ takes a function returning an int with no
$ argument as argument
......@@ -46,3 +50,18 @@ The ~make~ keyword allows the creation or definition of a function. Its name, be
A function can be called either by just typing its name if it has no arguments, as we can see on the calls on ~i~ above, or by typing its name then parenthesis with its arguments inside as we can see with the calls of ~a~, ~b~ and ~res~. A function can be passed as arguments without being evaluated by adding the symbol ~&~ before the name of the function, as we can see on the second to last line above.
Since ~a~, ~b~ and ~res~ were declared inside the declaration of ~fib~, this makes these function only available from within ~fib~ and cannot be called directly by the user.
As you can see above, comments are marked with the symbol ~$~, which makes any character following this symbol ignored by the compiler and the interpreter until the next line break. A multi-line comment is delimited by three ~$~ and cannot nest other multi-line comments (i.e. if a ~$$$~ happens, it either begins or ends a comment and cannot be a comment by itself).
Literal values can be given as-is, however their type will be inferred by the compiler and it might not infer the type the user wished for, hence it is recommended to use the built-in functions related to these types, such as ~Int(i: () -> int) -> int;~ which ensures that ~i~ is an ~int~. By default, an ~int~ is an signed integer on eight (8) bytes, similar to Rust’s ~i64~.
* Types
** Types available
- int :: signed integer coded on eight (8) bytes, similar to Rust’s ~i64~. Default integer, can be obtained with the built-in function ~Int(i: () -> int) -> int;~
** Types to come
- float :: signed float coded on four (4) bytes, similar to Rust’s ~f32~. Default floating point number, can be obtained with the built-in function ~Float(i: () -> float) -> float;~
- char :: signed character coded on one (1) byte, similar to Rust’s ~i8~. Default character type, can be obtained with the built-in function ~Char(i: () -> char) -> char;~
- uint :: unsigned integer coded on four (4) bytes, similar to Rust’s ~u32~. Default floating point number, can be obtained with the built-in function ~Uint(i: () -> uint) -> uint;~
- uchar :: unsigned character coded on one (1) byte, similar to Rust’s ~u8~. Default floating point number, can be obtained with the built-in function ~Uint(i: () -> uint) -> uint;~
** Changes to come
The default should be four (4) bytes for ~int~.
......@@ -16,7 +16,8 @@ mod lexer {
Make, // make
Exit, // exit // TODO: make it interpreter only
Integer(i64), // litteral integer
Integer(i32), // literal integer
// Float(f32), // literal float
Equals, // =
Plus, // +
Minus, // -
......@@ -51,8 +52,15 @@ mod lexer {
// numbers ////////////////////////////////////////////////////////////
// detects a litteral integer
// can end with an `i`
// r#"[0-9]+\.[0-9]+"# => {
// (if let Ok(i) = text.parse::<f32>() {
// Token::Float(i)
// } else {
// panic!("float {} is out of range", text)
// }, text)
// }
r#"[0-9]+"# => {
(if let Ok(i) = text.parse::<i64>() {
(if let Ok(i) = text.parse::<i32>() {
Token::Integer(i)
} else {
panic!("integer {} is out of range", text)
......@@ -156,7 +164,8 @@ mod ast {
Var(String),
Assign(String, Box<Expr>),
Print(Box<Expr>),
Literal(i64),
LiteralInt(i32),
// LiteralFloat(f32),
#[allow(dead_code)]
Exit,
}
......@@ -238,8 +247,12 @@ mod parser {
},
Integer(i) => Expr {
span: span!(),
node: Expr_::Literal(i),
node: Expr_::LiteralInt(i),
},
// Float(i) => Expr {
// span: span!(),
// node: Expr_::LiteralFloat(i),
// },
LParen assign[a] RParen => a
}
}
......@@ -255,12 +268,12 @@ mod interp {
use crate::ast::*;
use std::collections::HashMap;
pub fn interp(p: Program, mut env: &mut HashMap<String, i64>) {
pub fn interp(p: Program, mut env: &mut HashMap<String, i32>) {
for expr in &p.stmts {
interp_expr(&mut env, expr);
}
}
fn interp_expr(env: &mut HashMap<String, i64>, expr: &Expr) -> i64 {
fn interp_expr(env: &mut HashMap<String, i32>, expr: &Expr) -> i32 {
use crate::ast::Expr_::*;
match expr.node {
Add(ref a, ref b) => interp_expr(env, a) + interp_expr(env, b),
......@@ -273,7 +286,8 @@ mod interp {
val
}
Var(ref var) => *env.get(&var[..]).unwrap(),
Literal(lit) => lit,
LiteralInt(lit) => lit,
// LiteralFloat(lit) => lit,
Print(ref e) => {
let val = interp_expr(env, e);
println!("{}", val);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment