rxi / fe Goto Github PK
View Code? Open in Web Editor NEWA tiny, embeddable language implemented in ANSI C
License: MIT License
A tiny, embeddable language implemented in ANSI C
License: MIT License
For example (is nil ((mac () nil)))
returns nil
, although the macro expands to nil
and this should be equivalent to (is nil nil)
.
The problem is that when the macro is evaluated, the value of the original form is replaced by the result of the macro expansion and create new nil
object.
$ fe scripts/life.fe
>> iteration 1
(- # -)
(- # -)
(- # -)
>> iteration 2
(- - -)
(# # #)
(- - -)
>> iteration 3
(- # -)
(- # -)
(- # -)
>> iteration 4
(- - -)
(# # #)
(- - -)
error: dotted pair in argument list
=> (nth x (nth y grid))
=> (or (nth x (nth y grid)) 0)
=> (get-cell grid (- x 1) y)
=> (+ (get-cell grid (- x 1) (- y 1)) (get-cell grid (- x 1) y) (g
=> (let n (+ (get-cell grid (- x 1) (- y 1)) (get-cell grid (- x 1
=> (next-cell grid cell x y)
=> (f (car lst))
=> (cons (f (car lst)) res)
=> (= res (cons (f (car lst)) res))
=> (while lst (= res (cons (f (car lst)) res)) (= lst (cdr lst)))
=> (map (fn (cell) (= x (+ x 1)) (next-cell grid cell x y)) row)
=> (f (car lst))
=> (cons (f (car lst)) res)
=> (= res (cons (f (car lst)) res))
=> (while lst (= res (cons (f (car lst)) res)) (= lst (cdr lst)))
=> (map (fn (row) (= y (+ y 1)) (let x -1) (map (fn (cell) (= x (+
=> (next-grid grid)
=> (= grid (next-grid grid))
=> (while (<= i n) (print ">> iteration" i) (print-grid grid) (pri
Looking at your repositories I feel like someone still understands the meaning of minimalism, KISS and overall the art of programming. Kudos!
I'd like to ask few things as I'm overly curious about your motivation, background etc.
Do you use fe
in real projects or do you know about other projects using fe
?
What was the motivation to create fe
if you already made aria?
(somewhat related to (2)) Have you considered implementing a different programming paradigm than Lisp-like?
For embedded languages I personally like the "live AST" paradigm (any computation is a manipulation of AST - i.e. homomorphism like in Lisp, but a bit less cluttered ๐) used e.g. in TCL/Rebol/Red/Spry languages (Spry being my favorite).
I went through all of your repositories after searching for how to get OOP in lua
and found your very well-written repository on that topic. I really like your overall projects style and your choices.
I recently came across this tool for making tutorial like that, and I just finished studying this tutorial and I learnt ALOT, and was thinking to myself it would be very good if I could do something like that, and then I went through this repo.
I would like to make a tutorial for this repository, what do you think?
SAS/C Amiga Compiler 6.58
Copyright (c) 1988-1995 SAS Institute Inc.
====================
return (chr = fgetc(udata)) == (-1) ? '\0' : chr;
fe.c 550 Warning 85: return value mismatch for function "readfp"
Expecting "char", found "int"
Slink - Version 6.58
Copyright (c) 1988-1995 SAS Institute, Inc. All Rights Reserved.
SLINK Complete - Maximum code size = 89848 ($00015ef8) bytes
Final output file size = 27496 ($00006b68) bytes
A simple loop locks up:
(= i 0)
(while (< i 19000000)
(= i (+ i 1)))
Is there a preferred way to count?
In the P_FN
and P_MAC
case of eval
, we set va
to a newly allocated object containing (env . arg).
Afterwards, we call fe_nextarg
, discarding the return value and advancing the arg-list, which contains the argument list of the funtion and the expression itself.
But the previous value of arg
was already baked into va
, and arg
is not used anywhere later in eval
(and is local to it).
Therefore, is the fe_nextarg
line a no-op?
https://github.com/rxi/fe/blob/master/src/fe.c#L660
Recompilation with the call removed does not seem to change the behaviour of function declaration.
Whenever I attempt to run any of the scripts provided in fe/scripts using cel7 the window turns completely black, I am not sure if it's an issue in the files or if I am missing any requirements I did not know about, everything except the no input file
error returns a black screen, I have tried to run it through the command line but it gives the same result.
Is there any way to solve this? I am using Windows 11 if OS is relevant
how would I check the amount of arguments the user passed to a function, or at least check if there's an argument after the current one? I wanna make a function with 4 optional arguments
This problem can be solved by marking all pairs (just like garbage collection) before printing, and unmarking them afterwards. If marked object was found during printing, you should output something like ...
. But this will slow down fe_write()
twice.
What is a lisp without recursion? Not very useful.
Therefore it is a pity that with fe you cannot specify a recursive function, using 'let'. You are forced to use '=', but then the function gets global scope which is not always wanted.
Maybe there is a small modification possible to solve this problem?
The FE_TPTR
has no extra data to recognize how this should be marked (with fe_handlers(ctx)->mark
) or released (with fe_handlers(ctx)->gc
). In most cases, you need to change the data structure of data in ptr
to recognize it from handlers. Why not add handlers directly to the FE_TPTR
type?
The gensym
function can be very useful in macros. It can be effectively implemented by creating symbols that are not added to symlist
, so such symbols can be removed by the garbage collector and may not have a string representation.
This is how you can change the implementation of the for
macro from 'scripts/macros.fe' using gensym
:
(= for (mac (item lst . body)
(let for-iter (gensym))
(list 'do
(list 'let for-iter lst)
(list 'while for-iter
(list 'let item (list 'car for-iter))
(list '= for-iter (list 'cdr for-iter))
(cons 'do body)
)
)
))
It is assumed that for-iter
should not be visible when body
is called. I'm implemented it in my fork.
Firstly, I fully confess that I'm totally inept when it comes to writing C, so the answer here may very well to be to extend fe -- but I'm wondering about the best way to pass user input into a program written in fe -- either by pipe or by prompting for user input.
Thanks for publishing fe
! It's very cool. Turning on more compiler warnings (I enjoy strange hobbies) I found this:
// src/fe.c:203:49: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]
// if (type(a) == FE_TNUMBER) { return number(a) == number(b); }
// ~~~~~~~~~ ^ ~~~~~~~~~
I found that it is indeed a practical problem in the REPL: I have 2 expressions that print equal but for which is
returns nil
(correctly).
> (= x (/ 10.2 3))
nil
> x
3.4
> (= y (/ 30.6 9))
nil
> y
3.4
> (is x y)
nil
I propose 2 possible fixes in the C file below:
// src/fe.c:203:49: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]
// if (type(a) == FE_TNUMBER) { return number(a) == number(b); }
// ~~~~~~~~~ ^ ~~~~~~~~~
//
// You can see with Python 3 that there is a tiny bit of floating point error:
//
// >>> 10.2 / 3
// 3.4
// >>> 30.6 / 9
// 3.4000000000000004
// >>> 3 * 3.4
// 10.2
// >>> 9 * 3.4
// 30.599999999999998
// >>> (10.2 / 3) == (30.6 / 9)
// False
//
// In Python, we can deal with this using `math.isclose`.
//
// fe prints them the same (format string `%.7g`), but does equality on their
// bitwise representations. So you end up with an error you can't see in the
// REPL, nor fix using library functions.
//
// % ./fe
// > (= x (/ 10.2 3))
// nil
// > x
// 3.4
// > (= y (/ 30.6 9))
// nil
// > y
// 3.4
// > (is x y)
// nil
//
// Changing fe to use `%.7f` at least makes the error visible in the REPL. I see
// 2 paths to solving this: (1) provide `isclose` (`double_nearly_equal` in the
// C below) in the standard library; or (2) make `is` use `double_nearly_equal`
// for number objects. With either option, using `%.7f` might also help people
// see the issue.
#include <float.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
// Translated from [the original
// Java](https://floating-point-gui.de/errors/comparison/). If you want to use
// `float`, use `fabsf` and `FLT_*`. If you want to use `long double`, use
// `fabsl` and `LDBL_*`.
//
// See also
// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/.
static bool double_nearly_equal(double a, double b, double epsilon) {
const double absA = fabs(a);
const double absB = fabs(b);
const double diff = fabs(a - b);
// It's OK to turn this warning off for this limited section of code, because
// it's in the context of handling tiny errors.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
if (a == b) {
// Special case; handles infinities.
return true;
} else if (a == 0 || b == 0 || (absA + absB < DBL_MIN)) {
#pragma clang diagnostic pop
// Either a or b is zero, or both are extremely close to it. Relative error
// is less meaningful here.
return diff < (epsilon * DBL_MIN);
}
// Use relative error.
return diff / MIN((absA + absB), DBL_MAX) < epsilon;
}
int main(int count, char* arguments[]) {
if (count != 5) {
fprintf(stderr, "Usage: ./float_nearly_equal 10.2 3 30.6 9\n");
return -1;
}
const double a = strtod(arguments[1], NULL);
const double b = strtod(arguments[2], NULL);
const double c = strtod(arguments[3], NULL);
const double d = strtod(arguments[4], NULL);
const double r1 = a / b;
const double r2 = c / d;
printf("%.20f / %.20f (%.20f) == %.20f / %.20f (%.20f) : %d\n", a, b, r1, c, d, r2, r1 == r2);
printf("%.20f / %.20f double_nearly_equal %.20f / %.20f : %d\n", a, b, c, d,
double_nearly_equal(a / b, c / d, DBL_EPSILON));
}
Hi!
Mostly just writing this issue to say how freaking cool this project is. Readable code, good docs, permissible license. Looking forward to exploring the C API a bit. I'd be very curious to learn about your motivations for building fe, and if you use it inside of any other projects.
Oh yeah, right... erm, the issue. Have you ever considered adding a tiny top-level Makefile?
It would be nice to be able to build things with "make", clean things with "make clean", and install with "sudo make install". It would only be a small addition to the project, but it would provide a build system that is both consistent and familiar.
Hi @rxi !
I'm so interested in fe and liked it so much, However...
I didn't found any example/way about implementing Object-Oriented stuff for fe!
I tried to implement struct via this way:
(do
; Value from list by index
(= nth (fn (n lst)
(while (< 0 n)
(= n (- n 1))
(= lst (cdr lst)))
(if (is n 0) (car lst))
))
; Trick to make Structs ;)
; Create list storing cons(s), Like structs in C
(= obj (list
(cons "A" 1)
(cons "B" 2)
(cons "C" 3)
(cons "D" 4)
))
; Get struct prop (Remember that list works like array)
(print (car (nth 3 obj)))
(print (cdr (nth 3 obj)))
(if (is (car (nth 3 obj)) "D")
(print "STRUCTS IMPLEMENTATION WORKED!")
)
)
But i think this gets much difficult to get property of struct, Is there some way in C/fe to implement OOP stuff?
Thanks!
like if i had a fe file with the code:
(= input "hello there")
and i wanted to access the value of the input variable in c, how would i do that?
Thanks for fe -- a very nice tiny interpreter.
How could I make an eval
function (or macro)? i.e. such that
(= a '(+ 1 2))
(eval a)
=> 3
I tried using mac
and fn
but couldn't make it. Did I miss something obvious?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.