forked from ground/ground
Compare commits
52 Commits
0.0.1
...
e2a037befc
Author | SHA1 | Date | |
---|---|---|---|
e2a037befc | |||
38681f72d7 | |||
9c8cd58449 | |||
074b473bb1 | |||
a3b9cd2519 | |||
76205a613d | |||
7961195018 | |||
e73e5a7ebc | |||
06ed44a010 | |||
d8cc3ff9e0 | |||
f32f76450a | |||
cea66aa583 | |||
8d80416c5c | |||
0eb5670dfd | |||
8247ba36e4 | |||
76e36b7ca3 | |||
6596bfcc85 | |||
a9bfc1b0e3 | |||
c952be1fe6 | |||
1c5ca8d201 | |||
e56e6de911 | |||
38b17e7db5 | |||
e74e5ea548 | |||
f5140e3833 | |||
c01dd470e1 | |||
16660c6a8d | |||
5bd8519517 | |||
2f706e2285 | |||
db99b9ac9f | |||
e906734aca | |||
8da5a2bf93 | |||
e9600d8500 | |||
1c0dfcc4b7 | |||
f7f3972248 | |||
50d83aa228 | |||
14758df1ab | |||
b19b4123d8 | |||
28a9e389fa | |||
e4cc6b2f14 | |||
bb753e97d4 | |||
4cd4d9080d | |||
52eadaa9c3 | |||
db0c362efb | |||
3a8600b481 | |||
c39967a72f | |||
163f85b896 | |||
09033cd432 | |||
566d3aa0fb | |||
f8397e85d4 | |||
3f2482d7ea | |||
2e388c6e68 | |||
f43f79b869 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
ground
|
||||
Bobfile
|
||||
|
2
Bobfile
2
Bobfile
@@ -1,5 +1,5 @@
|
||||
compiler "g++";
|
||||
binary "ground";
|
||||
source "src/main.cpp";
|
||||
flag "O3";
|
||||
flag "Ofast";
|
||||
compile;
|
||||
|
@@ -8,7 +8,7 @@ Ground is an interpreter which processes and interprets Ground instructions. It
|
||||
|
||||
* **Simple syntax:** Ground doesn't have very many features, and that's intentional. It makes Ground easy to learn, and keeps it speedy.
|
||||
* **Super speed:** Ground code is faster than Python and JavaScript, and nearly as fast as C++ and Rust, while still being interpreted. (Tested using tests/to1000.grnd)
|
||||
* **Tiny interpreter:** Ground contains 761 lines of code (and 233 lines of comments) at the time of writing, and compiles in seconds.
|
||||
* **Tiny interpreter:** Ground contains 1482 lines of code (and 382 lines of comments) at the time of writing, and compiles in seconds.
|
||||
* **Portable:** Ground's code only uses features from the C++ standard library, using features from C++17 and prior.
|
||||
|
||||
## How do I get started?
|
||||
@@ -16,7 +16,7 @@ Ground is an interpreter which processes and interprets Ground instructions. It
|
||||
Clone the repo and compile with your favourite C++ compiler:
|
||||
|
||||
```
|
||||
g++ src/main.cpp -std=C++17 -O3 -o ground
|
||||
g++ src/main.cpp -std=c++17 -O3 -o ground
|
||||
```
|
||||
|
||||
(You can omit the -std flag on systems which default to the latest standard, and the -O3 flag if you're fine with a slightly slower interpreter.)
|
||||
|
107
docs/demos/calc.grnd
Executable file
107
docs/demos/calc.grnd
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env ground
|
||||
|
||||
@begin
|
||||
stdout "Calculation: "
|
||||
stdin &calc
|
||||
getstrsize $calc &calcsize
|
||||
set &counter 0
|
||||
set &left ""
|
||||
set &right ""
|
||||
set &operator ' '
|
||||
set &isRight false
|
||||
|
||||
## Preprocessing
|
||||
|
||||
# Loop to parse input
|
||||
@loopstart
|
||||
getstrcharat $calc $counter &char
|
||||
|
||||
# Remove any spaces (they're inconvenient)
|
||||
equal $char ' ' &cond
|
||||
if $cond %doneif
|
||||
|
||||
# Check for operators
|
||||
# '+' operator
|
||||
inequal '+' $char &cond
|
||||
if $cond %minusOpCheck
|
||||
set &operator $char
|
||||
set &isRight true
|
||||
jump %doneif
|
||||
|
||||
@minusOpCheck
|
||||
# '-' operator
|
||||
inequal '-' $char &cond
|
||||
if $cond %multiplyOpCheck
|
||||
set &operator $char
|
||||
set &isRight true
|
||||
jump %doneif
|
||||
|
||||
@multiplyOpCheck
|
||||
# '*' operator
|
||||
inequal '*' $char &cond
|
||||
if $cond %divideOpCheck
|
||||
set &operator $char
|
||||
set &isRight true
|
||||
jump %doneif
|
||||
|
||||
@divideOpCheck
|
||||
# '/' operator
|
||||
inequal '/' $char &cond
|
||||
if $cond %endOpChecks
|
||||
set &operator $char
|
||||
set &isRight true
|
||||
jump %doneif
|
||||
|
||||
@endOpChecks
|
||||
if $isRight %isRight
|
||||
add $left $char &left
|
||||
jump %doneif
|
||||
@isRight
|
||||
add $right $char &right
|
||||
@doneif
|
||||
add 1 $counter &counter
|
||||
inequal $counter $calcsize &cond
|
||||
if $cond %loopstart
|
||||
# End loop
|
||||
|
||||
## Computing
|
||||
|
||||
# Convert types
|
||||
stod $left &left
|
||||
stod $right &right
|
||||
|
||||
# Calculations
|
||||
# Adding
|
||||
inequal $operator '+' &cond
|
||||
if $cond %subtract
|
||||
add $left $right &result
|
||||
stdlnout $result
|
||||
jump %begin
|
||||
|
||||
# Subtracting
|
||||
@subtract
|
||||
inequal $operator '-' &cond
|
||||
if $cond %multiply
|
||||
subtract $left $right &result
|
||||
stdlnout $result
|
||||
jump %begin
|
||||
|
||||
# Multiplying
|
||||
@multiply
|
||||
inequal $operator '*' &cond
|
||||
if $cond %divide
|
||||
multiply $left $right &result
|
||||
stdlnout $result
|
||||
jump %begin
|
||||
|
||||
# Dividing
|
||||
@divide
|
||||
inequal $operator '/' &cond
|
||||
if $cond %error
|
||||
divide $left $right &result
|
||||
stdlnout $result
|
||||
jump %begin
|
||||
|
||||
@error
|
||||
stdlnout "Uh oh something terribly terrible happened lmao"
|
||||
jump %begin
|
70
docs/highlight.py
Normal file
70
docs/highlight.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
exit(1)
|
||||
|
||||
fileName = sys.argv[1]
|
||||
thefile = open(fileName).readlines()
|
||||
|
||||
def isnumber(num):
|
||||
try:
|
||||
float(num)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
allstr = ""
|
||||
color = ""
|
||||
keywords = ["if", "jump", "end", "stdin", "stdout", "stdlnout", "set", "gettype", "exists", "setlist", "setlistat", "getlistat", "getlistsize", "listappend", "getstrsize", "getstrcharat", "add", "subtract", "multiply", "divide", "equal", "inequal", "not", "greater", "lesser", "stoi", "stod", "tostring", "fun", "return", "endfun", "pusharg", "call", "use", "extern"]
|
||||
|
||||
for line in thefile:
|
||||
allstr += line + " <br> "
|
||||
|
||||
lines = len(allstr.split("<br>"))-1
|
||||
a = allstr.split()
|
||||
|
||||
for i in range(lines):
|
||||
instr = False
|
||||
incom = False
|
||||
words = len(allstr.split("<br>")[i].split())
|
||||
for j in range(words):
|
||||
tempword = allstr.split("<br>")[i].split()[j]
|
||||
if allstr.split("<br>")[i].split()[0][0] == "#":
|
||||
color = "\033[37m"
|
||||
elif allstr.split("<br>")[i].split()[0][0] == "@":
|
||||
color = "\033[32m"
|
||||
elif tempword in keywords:
|
||||
color = "\033[95m"
|
||||
elif isnumber(tempword) or tempword == "true" or tempword == "false":
|
||||
color = "\033[96m"
|
||||
elif tempword[0] == "#":
|
||||
incom = True
|
||||
color = "\033[37m"
|
||||
elif tempword[0] == "&":
|
||||
color = "\033[93m"
|
||||
elif tempword[0] == "$":
|
||||
color = "\033[33m"
|
||||
elif tempword[0] == "%":
|
||||
color = "\033[32m"
|
||||
elif tempword[0] == "-":
|
||||
color = "\033[34m"
|
||||
elif tempword[0] == "!":
|
||||
color = "\033[94m"
|
||||
elif tempword[0] == "*":
|
||||
color = "\033[93m"
|
||||
elif tempword[0] == "\"":
|
||||
color = "\033[92m"
|
||||
instr = not instr
|
||||
elif tempword[0] == "\'" and tempword[len(tempword)-1] == "\'":
|
||||
color = "\033[92m"
|
||||
elif instr:
|
||||
color = "\033[92m"
|
||||
elif incom:
|
||||
color = "\033[37m"
|
||||
else:
|
||||
color = "\033[91m"
|
||||
|
||||
print(f'{color}{tempword}', end=" ")
|
||||
print()
|
||||
|
||||
print("\033[00m", end="")
|
21
docs/library-guide.md
Normal file
21
docs/library-guide.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Guide to Writing Libraries in Ground
|
||||
|
||||
Ground has a "use" keyword which allows you to import libraries written in Ground, executing the code, and importing functions for use. This makes building reproducable bits of code very easy.
|
||||
|
||||
This is a guide of best practices which should be followed.
|
||||
|
||||
## .grnd file extension
|
||||
|
||||
The Ground interpreter will automatically append ".grnd" when you use a library. If you write `use "myLibrary"` Ground will look for "myLibrary.grnd". This is a must-do.
|
||||
|
||||
## camelCase Function and File Names
|
||||
|
||||
For consistency, please use camelCase (with a lower case first letter) when naming functions and file names.
|
||||
|
||||
## Don't use spaces
|
||||
|
||||
It is impossible to use spaces in Ground function names. Please do not use spaces in file names, even though it will work.
|
||||
|
||||
## Use functions for most operations
|
||||
|
||||
Where possible, create functions to do everything needed with your library. You can include some code for initialisation, but don't do the entirety of your operations outside of your functions.
|
184
docs/syntax.md
184
docs/syntax.md
@@ -1,6 +1,6 @@
|
||||
## Ground Syntax Guide
|
||||
|
||||
### General syntax
|
||||
## General syntax
|
||||
|
||||
Ground uses simple instructions and arguments to run code.
|
||||
|
||||
@@ -32,12 +32,38 @@ Reference a line (a line reference) with a percent symbol before a line number:
|
||||
jump %10
|
||||
```
|
||||
|
||||
### Keywords
|
||||
Alternatively, set a label:
|
||||
|
||||
```
|
||||
@myLabel # The '@' symbol denotes setting a label
|
||||
```
|
||||
|
||||
and jump to that (setting labels will be discussed below):
|
||||
|
||||
```
|
||||
jump %myLabel
|
||||
```
|
||||
|
||||
Reference a list (a list reference) with an asterisk:
|
||||
|
||||
```
|
||||
setlist *myList $value1 $value2 # and so on
|
||||
```
|
||||
|
||||
Add comments with a `#`:
|
||||
|
||||
```
|
||||
# This is a comment
|
||||
```
|
||||
|
||||
## Keywords
|
||||
|
||||
Note: &var can be replaced with any direct reference. $value can be replaced with a literal value or a value reference. %1 can be replaced with a line reference.
|
||||
|
||||
Note: In most of these functions, if a direct reference is used, the value outputted by that function will be avaliable at that variable. Any existing value inside that variable will be overwritten.
|
||||
|
||||
### Control Flow
|
||||
|
||||
#### if
|
||||
|
||||
Make a decision based on a boolean. If the boolean is true, jumps to the line referenced.
|
||||
@@ -54,7 +80,9 @@ Usage: `jump %1`
|
||||
|
||||
Ends the program. Requires an integer for a status code.
|
||||
|
||||
Usage: `end $value`
|
||||
Usage: `end $intvalue`
|
||||
|
||||
### I/O
|
||||
|
||||
#### stdin
|
||||
|
||||
@@ -74,12 +102,74 @@ Allows output to the console, appending a new line at the end.
|
||||
|
||||
Usage: `stdlnout $value`
|
||||
|
||||
### Variables and Lists
|
||||
|
||||
#### set
|
||||
|
||||
Allows you to set a variable to a value.
|
||||
|
||||
Usage: `set &var $value`
|
||||
|
||||
#### gettype
|
||||
|
||||
Gets the type of a variable. Outputs a string which can be "int", "double", "bool", "string", "char".
|
||||
|
||||
Usage: `gettype $value &var`
|
||||
|
||||
#### exists
|
||||
|
||||
Checks if a variable exists with a direct reference. If the variable exists, outputs true. Otherwise outputs false.
|
||||
|
||||
Usage `exists &var1 &var2`
|
||||
|
||||
Note: You can also replace &var1 with a list or line reference to check if it also exists
|
||||
|
||||
#### setlist
|
||||
|
||||
Allows you to initialize a list.
|
||||
|
||||
Usage: `setlist *list $value1 $value2 $value3...`
|
||||
|
||||
#### setlistat
|
||||
|
||||
Sets a list item at an index. The item at the index must already exist. Lists are index 0.
|
||||
|
||||
Usage: `setlistat *list $intvalue $value`
|
||||
|
||||
#### getlistat
|
||||
|
||||
Gets a list item at an index, and puts it in the variable provided. The item at the index must already exist. Lists are index 0.
|
||||
|
||||
Usage: `getlistat *list $intvalue &var`
|
||||
|
||||
#### getlistsize
|
||||
|
||||
Gets the size of a list and puts it in the variable provided.
|
||||
|
||||
Usage: `getlistsize *list &var`
|
||||
|
||||
#### listappend
|
||||
|
||||
Appends an item to a list.
|
||||
|
||||
Usage: `listappend *list $var`
|
||||
|
||||
### String Operations
|
||||
|
||||
#### getstrsize
|
||||
|
||||
Gets the size of a string and puts it in the variable provided.
|
||||
|
||||
Usage: `getstrsize $stringvalue &var`
|
||||
|
||||
#### getstrcharat
|
||||
|
||||
Gets a character at a certain position in a string and saves it to a variable.
|
||||
|
||||
Usage: `getstrcharat $stringvalue $intvalue &var`
|
||||
|
||||
### Maths
|
||||
|
||||
#### add
|
||||
|
||||
Adds two numbers. Numbers mean an integer or a double. Outputs to a direct reference.
|
||||
@@ -104,6 +194,8 @@ Divides two numbers. Numbers mean an integer or a double. Outputs to a direct re
|
||||
|
||||
Usage: `divide $value $value &var`
|
||||
|
||||
### Comparisons
|
||||
|
||||
#### equal
|
||||
|
||||
Checks if two values are equal. Outputs a boolean to a direct reference.
|
||||
@@ -116,6 +208,12 @@ Checks if two values are not equal. Outputs a boolean to a direct reference.
|
||||
|
||||
Usage: `inequal $value $value &var`
|
||||
|
||||
#### not
|
||||
|
||||
Negates a boolean.
|
||||
|
||||
Usage: `not $value &var`
|
||||
|
||||
#### greater
|
||||
|
||||
Checks if the left value is greater than the right value. Outputs a boolean to a direct reference.
|
||||
@@ -127,3 +225,83 @@ Usage: `greater $value $value &var`
|
||||
Checks if the left value is lesser than the right value. Outputs a boolean to a direct reference.
|
||||
|
||||
Usage: `lesser $value $value &var`
|
||||
|
||||
### Type Conversions
|
||||
|
||||
#### stoi
|
||||
|
||||
Converts a string to an integer. Throws an error if the string cannot be turned into an integer.
|
||||
|
||||
Usage: `stoi $stringvalue &var`
|
||||
|
||||
#### stod
|
||||
|
||||
Converts a string to a double. Throws an error if the string cannot be turned into a double.
|
||||
|
||||
Usage: `stod $stringvalue &var`
|
||||
|
||||
#### tostring
|
||||
|
||||
Converts any type to a string.
|
||||
|
||||
Usage: `tostring $value &var`
|
||||
|
||||
### Functions and function specific features (Experimental, please report bugs!)
|
||||
|
||||
Some symbols specific to this category:
|
||||
|
||||
* `!function`: A function reference
|
||||
|
||||
* `-type`: A type reference. Can be one of the following: "-string", "-char", "-int", "-double", "-bool"
|
||||
|
||||
#### fun
|
||||
|
||||
Defines a function. All code between `fun` and `endfun` will be included in the function.
|
||||
|
||||
Usage: `fun -type !functionname -type &var -type &var -type &var # and so on...`
|
||||
|
||||
Usage note: The first type specified before the function name must be the return type. The type displayed before all vars shows what type that variable must be.
|
||||
|
||||
#### return
|
||||
|
||||
Returns back to the main program (or other function that called this function). Also returns a value, which must be of the type defined when defining the function.
|
||||
|
||||
Usage: `return $value`
|
||||
|
||||
#### endfun
|
||||
|
||||
Ends a function definition. When a function reaches the end the argument list will be cleared.
|
||||
|
||||
Usage: `endfun`
|
||||
|
||||
#### pusharg
|
||||
|
||||
Adds a value to the argument list which will be passed to the function when it is called.
|
||||
|
||||
Usage: `pusharg $value`
|
||||
|
||||
#### call
|
||||
|
||||
Calls a function, with all the arguments in the argument list. The return value will be put in the specified variable.
|
||||
|
||||
Usage: `call !function &var
|
||||
|
||||
### Interacting with Libraries
|
||||
|
||||
#### use (Experimental, please report bugs!)
|
||||
|
||||
Attempts to import another Ground program. Gets inserted wherever the use statement is. Any code (including code outside function declarations) will be executed. All functions from the library will be given a prefix, meaning functions will be registered as `!libName:functionName`.
|
||||
|
||||
Note: Ground will check the directory where the program is being run from when trying to find imported programs. If that fails, it will check the directory set in the $GROUND_LIBS environment variable set by your system. The '.grnd' extension is appended automatically.
|
||||
|
||||
Usage: `use $stringvalue`
|
||||
|
||||
#### extern (Experimental, please report bugs!)
|
||||
|
||||
Attempts to import a shared object library written for Ground. All functions in the external library will be usable with `call`. All functions from the library will be given a prefix, meaning functions will be registered as `!libName:functionName`.
|
||||
|
||||
Note: Ground will check the directory set in the $GROUND_LIBS environment variable set by your system. The '.so' (Linux), '.dylib' (macOS), or '.dll' (Windows) extension is appended automatically.
|
||||
|
||||
Documentation on how to do external libraries coming soon.
|
||||
|
||||
Usage: `extern $stringvalue`
|
||||
|
25
docs/writing-a-program.md
Normal file
25
docs/writing-a-program.md
Normal file
@@ -0,0 +1,25 @@
|
||||
## Writing programs with Ground (WORK IN PROGRESS GUIDE)
|
||||
|
||||
Ground is a very easy language to learn. In this guide, you will learn how to write a simple calculator in Ground, as well as best practices (which there aren't many of, since Ground is so simple).
|
||||
|
||||
Note: This assumes you've read and understand the syntax.md document in this folder.
|
||||
|
||||
### Let's start!
|
||||
|
||||
Open a new file with the `.grnd` extension. Should look something like this:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
(Real empty in that file.)
|
||||
|
||||
Let's add some code! Create a label for the start, since we'll loop back once we've calculated, and ask for the user's input:
|
||||
|
||||
```
|
||||
@start
|
||||
stdout "Calculation: "
|
||||
stdin &calc
|
||||
```
|
||||
|
||||
At the calc variable, we have whatever the user typed in. This should look something like `9+10`, `1 / 3` or who knows what else. But first we should organise this data. Let's create a loop to iterate through this input, and a counter to keep moving forward:
|
9
extlibs/compiling.md
Normal file
9
extlibs/compiling.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## Compiling External Libraries
|
||||
|
||||
On Linux:
|
||||
|
||||
`g++ -shared -fPIC -o filename.so filename.cpp`
|
||||
|
||||
On macOS:
|
||||
|
||||
`g++ -shared -fPIC -o filename.dylib filename.cpp`
|
9
extlibs/exec/README.md
Normal file
9
extlibs/exec/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# exec library
|
||||
|
||||
This library allows executing third party executables via the C++ "system" command.
|
||||
|
||||
## Functions
|
||||
|
||||
### fun -int !exec -string &command
|
||||
|
||||
Runs a command on a system. Returns the status code of that command.
|
16
extlibs/exec/exec.cpp
Normal file
16
extlibs/exec/exec.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "ground_lib.h"
|
||||
|
||||
GroundValue exec(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_STRING);
|
||||
int exec = system(GET_STRING(args[0]));
|
||||
return GROUND_INT_VAL(exec);
|
||||
}
|
||||
|
||||
GROUND_LIBRARY_INTERFACE()
|
||||
|
||||
GROUND_LIBRARY_INIT()
|
||||
REGISTER_GROUND_FUNCTION(exec);
|
||||
GROUND_LIBRARY_INIT_END()
|
||||
|
||||
GROUND_LIBRARY_CLEANUP()
|
||||
GROUND_LIBRARY_CLEANUP_END()
|
193
extlibs/exec/ground_lib.h
Normal file
193
extlibs/exec/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#ifndef GROUND_LIB_H
|
||||
#define GROUND_LIB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// Ground types - must match the interpreter
|
||||
typedef enum {
|
||||
GROUND_INT,
|
||||
GROUND_DOUBLE,
|
||||
GROUND_BOOL,
|
||||
GROUND_STRING,
|
||||
GROUND_CHAR
|
||||
} GroundType;
|
||||
|
||||
typedef struct {
|
||||
GroundType type;
|
||||
union {
|
||||
int int_val;
|
||||
double double_val;
|
||||
int bool_val;
|
||||
char* string_val;
|
||||
char char_val;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
// Helper macros for creating GroundValue objects
|
||||
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||
|
||||
// Helper function for creating string values
|
||||
inline GroundValue ground_string_val(const std::string& str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
char* result_str = new char[str.length() + 1];
|
||||
std::strcpy(result_str, str.c_str());
|
||||
v.data.string_val = result_str;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper function for creating string values from C strings
|
||||
inline GroundValue ground_cstring_val(const char* str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
if (str) {
|
||||
size_t len = std::strlen(str);
|
||||
char* result_str = new char[len + 1];
|
||||
std::strcpy(result_str, str);
|
||||
v.data.string_val = result_str;
|
||||
} else {
|
||||
v.data.string_val = nullptr;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper macros for type checking
|
||||
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||
|
||||
// Helper macros for extracting values
|
||||
#define GET_INT(v) ((v).data.int_val)
|
||||
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||
#define GET_STRING(v) ((v).data.string_val)
|
||||
#define GET_CHAR(v) ((v).data.char_val)
|
||||
|
||||
// Helper macros for argument validation
|
||||
#define REQUIRE_ARGS(count) \
|
||||
if (arg_count < (count)) { \
|
||||
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||
if (args[arg_index].type != expected_type) { \
|
||||
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
// Convenience macro for checking both arg count and types
|
||||
#define VALIDATE_ARGS_1(type1) \
|
||||
REQUIRE_ARGS(1); \
|
||||
REQUIRE_TYPE(0, type1);
|
||||
|
||||
#define VALIDATE_ARGS_2(type1, type2) \
|
||||
REQUIRE_ARGS(2); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2);
|
||||
|
||||
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||
REQUIRE_ARGS(3); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2); \
|
||||
REQUIRE_TYPE(2, type3);
|
||||
|
||||
// Function registration helpers
|
||||
class GroundLibrary {
|
||||
private:
|
||||
std::vector<std::string> function_names;
|
||||
std::vector<void*> function_pointers;
|
||||
|
||||
public:
|
||||
void register_function(const std::string& name, void* ptr) {
|
||||
function_names.push_back(name);
|
||||
function_pointers.push_back(ptr);
|
||||
}
|
||||
|
||||
const char** get_function_names() {
|
||||
static std::vector<const char*> names;
|
||||
names.clear();
|
||||
for (const auto& name : function_names) {
|
||||
names.push_back(name.c_str());
|
||||
}
|
||||
names.push_back(nullptr); // Null terminator
|
||||
return names.data();
|
||||
}
|
||||
|
||||
void* get_function(const char* name) {
|
||||
for (size_t i = 0; i < function_names.size(); i++) {
|
||||
if (function_names[i] == name) {
|
||||
return function_pointers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Global library instance
|
||||
extern GroundLibrary ground_lib_registry;
|
||||
|
||||
// Macro to register functions easily
|
||||
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||
|
||||
// Macro to define the library interface
|
||||
#define GROUND_LIBRARY_INTERFACE() \
|
||||
GroundLibrary ground_lib_registry; \
|
||||
extern "C" { \
|
||||
const char** ground_get_functions() { \
|
||||
return ground_lib_registry.get_function_names(); \
|
||||
} \
|
||||
void* ground_get_function(const char* name) { \
|
||||
return ground_lib_registry.get_function(name); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional initialization macro
|
||||
#define GROUND_LIBRARY_INIT() \
|
||||
extern "C" { \
|
||||
void ground_lib_init() {
|
||||
|
||||
#define GROUND_LIBRARY_INIT_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional cleanup macro
|
||||
#define GROUND_LIBRARY_CLEANUP() \
|
||||
extern "C" { \
|
||||
void ground_lib_cleanup() {
|
||||
|
||||
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Utility function to print GroundValue for debugging
|
||||
inline void debug_print_ground_value(const GroundValue& v) {
|
||||
switch (v.type) {
|
||||
case GROUND_INT:
|
||||
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||
break;
|
||||
case GROUND_DOUBLE:
|
||||
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||
break;
|
||||
case GROUND_BOOL:
|
||||
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||
break;
|
||||
case GROUND_STRING:
|
||||
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||
break;
|
||||
case GROUND_CHAR:
|
||||
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GROUND_LIB_H
|
13
extlibs/file/README.md
Normal file
13
extlibs/file/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# file library
|
||||
|
||||
This library allows reading from and writing to files on the system.
|
||||
|
||||
## Functions
|
||||
|
||||
### fun -string !readFile -string &fileName
|
||||
|
||||
This function reads all content from a file and returns it.
|
||||
|
||||
### fun -bool !writeFile -string &fileName -string &content
|
||||
|
||||
This function overwrites a file with specified content. If successful, returns true. If not successful, returns false, and prints out a reason why it didn't work.
|
43
extlibs/file/file.cpp
Normal file
43
extlibs/file/file.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "ground_lib.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
GroundValue readFile(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_STRING);
|
||||
|
||||
std::ifstream ffile(GET_STRING(args[0]));
|
||||
|
||||
std::string tmp;
|
||||
std::string out;
|
||||
|
||||
while (std::getline(ffile, tmp)) {
|
||||
out += tmp + "\n";
|
||||
}
|
||||
|
||||
return ground_string_val(out);
|
||||
}
|
||||
|
||||
GroundValue writeFile(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_2(GROUND_STRING, GROUND_STRING);
|
||||
|
||||
std::ofstream file(GET_STRING(args[0]));
|
||||
if (file.good()) {
|
||||
file << GET_STRING(args[1]);
|
||||
} else {
|
||||
std::cout << "File isn't good for writing in" << std::endl;
|
||||
return GROUND_BOOL_VAL(false);
|
||||
}
|
||||
|
||||
return GROUND_BOOL_VAL(true);
|
||||
}
|
||||
|
||||
GROUND_LIBRARY_INTERFACE()
|
||||
|
||||
GROUND_LIBRARY_INIT()
|
||||
REGISTER_GROUND_FUNCTION(readFile);
|
||||
REGISTER_GROUND_FUNCTION(writeFile);
|
||||
GROUND_LIBRARY_INIT_END()
|
||||
|
||||
GROUND_LIBRARY_CLEANUP()
|
||||
GROUND_LIBRARY_CLEANUP_END()
|
193
extlibs/file/ground_lib.h
Normal file
193
extlibs/file/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#ifndef GROUND_LIB_H
|
||||
#define GROUND_LIB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// Ground types - must match the interpreter
|
||||
typedef enum {
|
||||
GROUND_INT,
|
||||
GROUND_DOUBLE,
|
||||
GROUND_BOOL,
|
||||
GROUND_STRING,
|
||||
GROUND_CHAR
|
||||
} GroundType;
|
||||
|
||||
typedef struct {
|
||||
GroundType type;
|
||||
union {
|
||||
int int_val;
|
||||
double double_val;
|
||||
int bool_val;
|
||||
char* string_val;
|
||||
char char_val;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
// Helper macros for creating GroundValue objects
|
||||
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||
|
||||
// Helper function for creating string values
|
||||
inline GroundValue ground_string_val(const std::string& str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
char* result_str = new char[str.length() + 1];
|
||||
std::strcpy(result_str, str.c_str());
|
||||
v.data.string_val = result_str;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper function for creating string values from C strings
|
||||
inline GroundValue ground_cstring_val(const char* str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
if (str) {
|
||||
size_t len = std::strlen(str);
|
||||
char* result_str = new char[len + 1];
|
||||
std::strcpy(result_str, str);
|
||||
v.data.string_val = result_str;
|
||||
} else {
|
||||
v.data.string_val = nullptr;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper macros for type checking
|
||||
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||
|
||||
// Helper macros for extracting values
|
||||
#define GET_INT(v) ((v).data.int_val)
|
||||
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||
#define GET_STRING(v) ((v).data.string_val)
|
||||
#define GET_CHAR(v) ((v).data.char_val)
|
||||
|
||||
// Helper macros for argument validation
|
||||
#define REQUIRE_ARGS(count) \
|
||||
if (arg_count < (count)) { \
|
||||
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||
if (args[arg_index].type != expected_type) { \
|
||||
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
// Convenience macro for checking both arg count and types
|
||||
#define VALIDATE_ARGS_1(type1) \
|
||||
REQUIRE_ARGS(1); \
|
||||
REQUIRE_TYPE(0, type1);
|
||||
|
||||
#define VALIDATE_ARGS_2(type1, type2) \
|
||||
REQUIRE_ARGS(2); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2);
|
||||
|
||||
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||
REQUIRE_ARGS(3); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2); \
|
||||
REQUIRE_TYPE(2, type3);
|
||||
|
||||
// Function registration helpers
|
||||
class GroundLibrary {
|
||||
private:
|
||||
std::vector<std::string> function_names;
|
||||
std::vector<void*> function_pointers;
|
||||
|
||||
public:
|
||||
void register_function(const std::string& name, void* ptr) {
|
||||
function_names.push_back(name);
|
||||
function_pointers.push_back(ptr);
|
||||
}
|
||||
|
||||
const char** get_function_names() {
|
||||
static std::vector<const char*> names;
|
||||
names.clear();
|
||||
for (const auto& name : function_names) {
|
||||
names.push_back(name.c_str());
|
||||
}
|
||||
names.push_back(nullptr); // Null terminator
|
||||
return names.data();
|
||||
}
|
||||
|
||||
void* get_function(const char* name) {
|
||||
for (size_t i = 0; i < function_names.size(); i++) {
|
||||
if (function_names[i] == name) {
|
||||
return function_pointers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Global library instance
|
||||
extern GroundLibrary ground_lib_registry;
|
||||
|
||||
// Macro to register functions easily
|
||||
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||
|
||||
// Macro to define the library interface
|
||||
#define GROUND_LIBRARY_INTERFACE() \
|
||||
GroundLibrary ground_lib_registry; \
|
||||
extern "C" { \
|
||||
const char** ground_get_functions() { \
|
||||
return ground_lib_registry.get_function_names(); \
|
||||
} \
|
||||
void* ground_get_function(const char* name) { \
|
||||
return ground_lib_registry.get_function(name); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional initialization macro
|
||||
#define GROUND_LIBRARY_INIT() \
|
||||
extern "C" { \
|
||||
void ground_lib_init() {
|
||||
|
||||
#define GROUND_LIBRARY_INIT_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional cleanup macro
|
||||
#define GROUND_LIBRARY_CLEANUP() \
|
||||
extern "C" { \
|
||||
void ground_lib_cleanup() {
|
||||
|
||||
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Utility function to print GroundValue for debugging
|
||||
inline void debug_print_ground_value(const GroundValue& v) {
|
||||
switch (v.type) {
|
||||
case GROUND_INT:
|
||||
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||
break;
|
||||
case GROUND_DOUBLE:
|
||||
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||
break;
|
||||
case GROUND_BOOL:
|
||||
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||
break;
|
||||
case GROUND_STRING:
|
||||
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||
break;
|
||||
case GROUND_CHAR:
|
||||
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GROUND_LIB_H
|
193
extlibs/ground_lib.h
Normal file
193
extlibs/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#ifndef GROUND_LIB_H
|
||||
#define GROUND_LIB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// Ground types - must match the interpreter
|
||||
typedef enum {
|
||||
GROUND_INT,
|
||||
GROUND_DOUBLE,
|
||||
GROUND_BOOL,
|
||||
GROUND_STRING,
|
||||
GROUND_CHAR
|
||||
} GroundType;
|
||||
|
||||
typedef struct {
|
||||
GroundType type;
|
||||
union {
|
||||
int int_val;
|
||||
double double_val;
|
||||
int bool_val;
|
||||
char* string_val;
|
||||
char char_val;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
// Helper macros for creating GroundValue objects
|
||||
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||
|
||||
// Helper function for creating string values
|
||||
inline GroundValue ground_string_val(const std::string& str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
char* result_str = new char[str.length() + 1];
|
||||
std::strcpy(result_str, str.c_str());
|
||||
v.data.string_val = result_str;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper function for creating string values from C strings
|
||||
inline GroundValue ground_cstring_val(const char* str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
if (str) {
|
||||
size_t len = std::strlen(str);
|
||||
char* result_str = new char[len + 1];
|
||||
std::strcpy(result_str, str);
|
||||
v.data.string_val = result_str;
|
||||
} else {
|
||||
v.data.string_val = nullptr;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper macros for type checking
|
||||
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||
|
||||
// Helper macros for extracting values
|
||||
#define GET_INT(v) ((v).data.int_val)
|
||||
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||
#define GET_STRING(v) ((v).data.string_val)
|
||||
#define GET_CHAR(v) ((v).data.char_val)
|
||||
|
||||
// Helper macros for argument validation
|
||||
#define REQUIRE_ARGS(count) \
|
||||
if (arg_count < (count)) { \
|
||||
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||
if (args[arg_index].type != expected_type) { \
|
||||
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
// Convenience macro for checking both arg count and types
|
||||
#define VALIDATE_ARGS_1(type1) \
|
||||
REQUIRE_ARGS(1); \
|
||||
REQUIRE_TYPE(0, type1);
|
||||
|
||||
#define VALIDATE_ARGS_2(type1, type2) \
|
||||
REQUIRE_ARGS(2); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2);
|
||||
|
||||
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||
REQUIRE_ARGS(3); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2); \
|
||||
REQUIRE_TYPE(2, type3);
|
||||
|
||||
// Function registration helpers
|
||||
class GroundLibrary {
|
||||
private:
|
||||
std::vector<std::string> function_names;
|
||||
std::vector<void*> function_pointers;
|
||||
|
||||
public:
|
||||
void register_function(const std::string& name, void* ptr) {
|
||||
function_names.push_back(name);
|
||||
function_pointers.push_back(ptr);
|
||||
}
|
||||
|
||||
const char** get_function_names() {
|
||||
static std::vector<const char*> names;
|
||||
names.clear();
|
||||
for (const auto& name : function_names) {
|
||||
names.push_back(name.c_str());
|
||||
}
|
||||
names.push_back(nullptr); // Null terminator
|
||||
return names.data();
|
||||
}
|
||||
|
||||
void* get_function(const char* name) {
|
||||
for (size_t i = 0; i < function_names.size(); i++) {
|
||||
if (function_names[i] == name) {
|
||||
return function_pointers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Global library instance
|
||||
extern GroundLibrary ground_lib_registry;
|
||||
|
||||
// Macro to register functions easily
|
||||
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||
|
||||
// Macro to define the library interface
|
||||
#define GROUND_LIBRARY_INTERFACE() \
|
||||
GroundLibrary ground_lib_registry; \
|
||||
extern "C" { \
|
||||
const char** ground_get_functions() { \
|
||||
return ground_lib_registry.get_function_names(); \
|
||||
} \
|
||||
void* ground_get_function(const char* name) { \
|
||||
return ground_lib_registry.get_function(name); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional initialization macro
|
||||
#define GROUND_LIBRARY_INIT() \
|
||||
extern "C" { \
|
||||
void ground_lib_init() {
|
||||
|
||||
#define GROUND_LIBRARY_INIT_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional cleanup macro
|
||||
#define GROUND_LIBRARY_CLEANUP() \
|
||||
extern "C" { \
|
||||
void ground_lib_cleanup() {
|
||||
|
||||
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Utility function to print GroundValue for debugging
|
||||
inline void debug_print_ground_value(const GroundValue& v) {
|
||||
switch (v.type) {
|
||||
case GROUND_INT:
|
||||
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||
break;
|
||||
case GROUND_DOUBLE:
|
||||
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||
break;
|
||||
case GROUND_BOOL:
|
||||
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||
break;
|
||||
case GROUND_STRING:
|
||||
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||
break;
|
||||
case GROUND_CHAR:
|
||||
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GROUND_LIB_H
|
45
extlibs/math/README.md
Normal file
45
extlibs/math/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# math library
|
||||
|
||||
This library adds extra math functions to Ground.
|
||||
|
||||
## Functions
|
||||
|
||||
### fun -double !sinVal -double &input
|
||||
|
||||
Gets the sin of input.
|
||||
|
||||
### fun -double !cosVal -double &input
|
||||
|
||||
Gets the cos of input.
|
||||
|
||||
### fun -double !tanVal -double &input
|
||||
|
||||
Gets the tan of input.
|
||||
|
||||
### fun -double !sqrtVal -double &input
|
||||
|
||||
Gets the square root of input.
|
||||
|
||||
### fun -int !modVal -int &a -int &b
|
||||
|
||||
Gets the remainder of a divided by b.
|
||||
|
||||
### fun -double !floorVal -double &input
|
||||
|
||||
Gets the floor of input.
|
||||
|
||||
### fun -double !ceilVal -double &input
|
||||
|
||||
Gets the ceil of input.
|
||||
|
||||
### fun -double !roundVal -double &input
|
||||
|
||||
Rounds the input to the nearest integer.
|
||||
|
||||
### fun -int !randomInt -int &min -int &max
|
||||
|
||||
Gets a random integer between min and max (inclusive).
|
||||
|
||||
### fun -double !randomDouble -double &min -double &max
|
||||
|
||||
Gets a random double between min and max (inclusive).
|
193
extlibs/math/ground_lib.h
Normal file
193
extlibs/math/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#ifndef GROUND_LIB_H
|
||||
#define GROUND_LIB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// Ground types - must match the interpreter
|
||||
typedef enum {
|
||||
GROUND_INT,
|
||||
GROUND_DOUBLE,
|
||||
GROUND_BOOL,
|
||||
GROUND_STRING,
|
||||
GROUND_CHAR
|
||||
} GroundType;
|
||||
|
||||
typedef struct {
|
||||
GroundType type;
|
||||
union {
|
||||
int int_val;
|
||||
double double_val;
|
||||
int bool_val;
|
||||
char* string_val;
|
||||
char char_val;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
// Helper macros for creating GroundValue objects
|
||||
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||
|
||||
// Helper function for creating string values
|
||||
inline GroundValue ground_string_val(const std::string& str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
char* result_str = new char[str.length() + 1];
|
||||
std::strcpy(result_str, str.c_str());
|
||||
v.data.string_val = result_str;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper function for creating string values from C strings
|
||||
inline GroundValue ground_cstring_val(const char* str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
if (str) {
|
||||
size_t len = std::strlen(str);
|
||||
char* result_str = new char[len + 1];
|
||||
std::strcpy(result_str, str);
|
||||
v.data.string_val = result_str;
|
||||
} else {
|
||||
v.data.string_val = nullptr;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper macros for type checking
|
||||
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||
|
||||
// Helper macros for extracting values
|
||||
#define GET_INT(v) ((v).data.int_val)
|
||||
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||
#define GET_STRING(v) ((v).data.string_val)
|
||||
#define GET_CHAR(v) ((v).data.char_val)
|
||||
|
||||
// Helper macros for argument validation
|
||||
#define REQUIRE_ARGS(count) \
|
||||
if (arg_count < (count)) { \
|
||||
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||
if (args[arg_index].type != expected_type) { \
|
||||
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
// Convenience macro for checking both arg count and types
|
||||
#define VALIDATE_ARGS_1(type1) \
|
||||
REQUIRE_ARGS(1); \
|
||||
REQUIRE_TYPE(0, type1);
|
||||
|
||||
#define VALIDATE_ARGS_2(type1, type2) \
|
||||
REQUIRE_ARGS(2); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2);
|
||||
|
||||
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||
REQUIRE_ARGS(3); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2); \
|
||||
REQUIRE_TYPE(2, type3);
|
||||
|
||||
// Function registration helpers
|
||||
class GroundLibrary {
|
||||
private:
|
||||
std::vector<std::string> function_names;
|
||||
std::vector<void*> function_pointers;
|
||||
|
||||
public:
|
||||
void register_function(const std::string& name, void* ptr) {
|
||||
function_names.push_back(name);
|
||||
function_pointers.push_back(ptr);
|
||||
}
|
||||
|
||||
const char** get_function_names() {
|
||||
static std::vector<const char*> names;
|
||||
names.clear();
|
||||
for (const auto& name : function_names) {
|
||||
names.push_back(name.c_str());
|
||||
}
|
||||
names.push_back(nullptr); // Null terminator
|
||||
return names.data();
|
||||
}
|
||||
|
||||
void* get_function(const char* name) {
|
||||
for (size_t i = 0; i < function_names.size(); i++) {
|
||||
if (function_names[i] == name) {
|
||||
return function_pointers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Global library instance
|
||||
extern GroundLibrary ground_lib_registry;
|
||||
|
||||
// Macro to register functions easily
|
||||
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||
|
||||
// Macro to define the library interface
|
||||
#define GROUND_LIBRARY_INTERFACE() \
|
||||
GroundLibrary ground_lib_registry; \
|
||||
extern "C" { \
|
||||
const char** ground_get_functions() { \
|
||||
return ground_lib_registry.get_function_names(); \
|
||||
} \
|
||||
void* ground_get_function(const char* name) { \
|
||||
return ground_lib_registry.get_function(name); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional initialization macro
|
||||
#define GROUND_LIBRARY_INIT() \
|
||||
extern "C" { \
|
||||
void ground_lib_init() {
|
||||
|
||||
#define GROUND_LIBRARY_INIT_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional cleanup macro
|
||||
#define GROUND_LIBRARY_CLEANUP() \
|
||||
extern "C" { \
|
||||
void ground_lib_cleanup() {
|
||||
|
||||
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Utility function to print GroundValue for debugging
|
||||
inline void debug_print_ground_value(const GroundValue& v) {
|
||||
switch (v.type) {
|
||||
case GROUND_INT:
|
||||
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||
break;
|
||||
case GROUND_DOUBLE:
|
||||
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||
break;
|
||||
case GROUND_BOOL:
|
||||
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||
break;
|
||||
case GROUND_STRING:
|
||||
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||
break;
|
||||
case GROUND_CHAR:
|
||||
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GROUND_LIB_H
|
79
extlibs/math/math.cpp
Normal file
79
extlibs/math/math.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "ground_lib.h"
|
||||
#include <cmath>
|
||||
#include <random>
|
||||
|
||||
// Math functions
|
||||
GroundValue sinVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(sin(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue cosVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(cos(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue tanVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(tan(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue sqrtVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(sqrt(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue modVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_2(GROUND_INT, GROUND_INT);
|
||||
return GROUND_INT_VAL(GET_INT(args[0]) % GET_INT(args[1]));
|
||||
}
|
||||
|
||||
GroundValue floorVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(floor(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue ceilVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(ceil(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue roundVal(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_DOUBLE);
|
||||
return GROUND_DOUBLE_VAL(round(GET_DOUBLE(args[0])));
|
||||
}
|
||||
|
||||
GroundValue randomInt(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_2(GROUND_INT, GROUND_INT);
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> distrib(GET_INT(args[0]), GET_INT(args[1]));
|
||||
return GROUND_INT_VAL(distrib(gen));
|
||||
}
|
||||
|
||||
GroundValue randomDouble(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_2(GROUND_DOUBLE, GROUND_DOUBLE);
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_real_distribution<> distrib(GET_DOUBLE(args[0]), GET_DOUBLE(args[1]));
|
||||
return GROUND_DOUBLE_VAL(distrib(gen));
|
||||
}
|
||||
|
||||
// Library setup
|
||||
GROUND_LIBRARY_INTERFACE()
|
||||
|
||||
GROUND_LIBRARY_INIT()
|
||||
REGISTER_GROUND_FUNCTION(sinVal);
|
||||
REGISTER_GROUND_FUNCTION(cosVal);
|
||||
REGISTER_GROUND_FUNCTION(tanVal);
|
||||
REGISTER_GROUND_FUNCTION(sqrtVal);
|
||||
REGISTER_GROUND_FUNCTION(modVal);
|
||||
REGISTER_GROUND_FUNCTION(floorVal);
|
||||
REGISTER_GROUND_FUNCTION(ceilVal);
|
||||
REGISTER_GROUND_FUNCTION(roundVal);
|
||||
REGISTER_GROUND_FUNCTION(randomInt);
|
||||
REGISTER_GROUND_FUNCTION(randomDouble);
|
||||
GROUND_LIBRARY_INIT_END()
|
||||
|
||||
GROUND_LIBRARY_CLEANUP()
|
||||
GROUND_LIBRARY_CLEANUP_END()
|
13
extlibs/request/README.md
Normal file
13
extlibs/request/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# request library
|
||||
|
||||
This library allows various web requests from within Ground.
|
||||
|
||||
## Functions
|
||||
|
||||
### fun -string !simpleRequest -string &url
|
||||
|
||||
Makes a web request to a URL, and returns the contents. If the request is not successful, returns a response beginning with "Error code", and prints it to the console.
|
||||
|
||||
### fun -bool !saveContents -string &url -string &location
|
||||
|
||||
Makes a web request to a URL, and saves the contents to a file. If successful, returns true. If not, returns false.
|
193
extlibs/request/ground_lib.h
Normal file
193
extlibs/request/ground_lib.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#ifndef GROUND_LIB_H
|
||||
#define GROUND_LIB_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
// Ground types - must match the interpreter
|
||||
typedef enum {
|
||||
GROUND_INT,
|
||||
GROUND_DOUBLE,
|
||||
GROUND_BOOL,
|
||||
GROUND_STRING,
|
||||
GROUND_CHAR
|
||||
} GroundType;
|
||||
|
||||
typedef struct {
|
||||
GroundType type;
|
||||
union {
|
||||
int int_val;
|
||||
double double_val;
|
||||
int bool_val;
|
||||
char* string_val;
|
||||
char char_val;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
// Helper macros for creating GroundValue objects
|
||||
#define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
|
||||
#define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
|
||||
#define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
|
||||
#define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
|
||||
|
||||
// Helper function for creating string values
|
||||
inline GroundValue ground_string_val(const std::string& str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
char* result_str = new char[str.length() + 1];
|
||||
std::strcpy(result_str, str.c_str());
|
||||
v.data.string_val = result_str;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper function for creating string values from C strings
|
||||
inline GroundValue ground_cstring_val(const char* str) {
|
||||
GroundValue v;
|
||||
v.type = GROUND_STRING;
|
||||
if (str) {
|
||||
size_t len = std::strlen(str);
|
||||
char* result_str = new char[len + 1];
|
||||
std::strcpy(result_str, str);
|
||||
v.data.string_val = result_str;
|
||||
} else {
|
||||
v.data.string_val = nullptr;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Helper macros for type checking
|
||||
#define IS_INT(v) ((v).type == GROUND_INT)
|
||||
#define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
|
||||
#define IS_BOOL(v) ((v).type == GROUND_BOOL)
|
||||
#define IS_STRING(v) ((v).type == GROUND_STRING)
|
||||
#define IS_CHAR(v) ((v).type == GROUND_CHAR)
|
||||
|
||||
// Helper macros for extracting values
|
||||
#define GET_INT(v) ((v).data.int_val)
|
||||
#define GET_DOUBLE(v) ((v).data.double_val)
|
||||
#define GET_BOOL(v) ((v).data.bool_val != 0)
|
||||
#define GET_STRING(v) ((v).data.string_val)
|
||||
#define GET_CHAR(v) ((v).data.char_val)
|
||||
|
||||
// Helper macros for argument validation
|
||||
#define REQUIRE_ARGS(count) \
|
||||
if (arg_count < (count)) { \
|
||||
std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
#define REQUIRE_TYPE(arg_index, expected_type) \
|
||||
if (args[arg_index].type != expected_type) { \
|
||||
std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \
|
||||
return GROUND_BOOL_VAL(false); \
|
||||
}
|
||||
|
||||
// Convenience macro for checking both arg count and types
|
||||
#define VALIDATE_ARGS_1(type1) \
|
||||
REQUIRE_ARGS(1); \
|
||||
REQUIRE_TYPE(0, type1);
|
||||
|
||||
#define VALIDATE_ARGS_2(type1, type2) \
|
||||
REQUIRE_ARGS(2); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2);
|
||||
|
||||
#define VALIDATE_ARGS_3(type1, type2, type3) \
|
||||
REQUIRE_ARGS(3); \
|
||||
REQUIRE_TYPE(0, type1); \
|
||||
REQUIRE_TYPE(1, type2); \
|
||||
REQUIRE_TYPE(2, type3);
|
||||
|
||||
// Function registration helpers
|
||||
class GroundLibrary {
|
||||
private:
|
||||
std::vector<std::string> function_names;
|
||||
std::vector<void*> function_pointers;
|
||||
|
||||
public:
|
||||
void register_function(const std::string& name, void* ptr) {
|
||||
function_names.push_back(name);
|
||||
function_pointers.push_back(ptr);
|
||||
}
|
||||
|
||||
const char** get_function_names() {
|
||||
static std::vector<const char*> names;
|
||||
names.clear();
|
||||
for (const auto& name : function_names) {
|
||||
names.push_back(name.c_str());
|
||||
}
|
||||
names.push_back(nullptr); // Null terminator
|
||||
return names.data();
|
||||
}
|
||||
|
||||
void* get_function(const char* name) {
|
||||
for (size_t i = 0; i < function_names.size(); i++) {
|
||||
if (function_names[i] == name) {
|
||||
return function_pointers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// Global library instance
|
||||
extern GroundLibrary ground_lib_registry;
|
||||
|
||||
// Macro to register functions easily
|
||||
#define REGISTER_GROUND_FUNCTION(func_name) \
|
||||
ground_lib_registry.register_function(#func_name, (void*)func_name)
|
||||
|
||||
// Macro to define the library interface
|
||||
#define GROUND_LIBRARY_INTERFACE() \
|
||||
GroundLibrary ground_lib_registry; \
|
||||
extern "C" { \
|
||||
const char** ground_get_functions() { \
|
||||
return ground_lib_registry.get_function_names(); \
|
||||
} \
|
||||
void* ground_get_function(const char* name) { \
|
||||
return ground_lib_registry.get_function(name); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional initialization macro
|
||||
#define GROUND_LIBRARY_INIT() \
|
||||
extern "C" { \
|
||||
void ground_lib_init() {
|
||||
|
||||
#define GROUND_LIBRARY_INIT_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Optional cleanup macro
|
||||
#define GROUND_LIBRARY_CLEANUP() \
|
||||
extern "C" { \
|
||||
void ground_lib_cleanup() {
|
||||
|
||||
#define GROUND_LIBRARY_CLEANUP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
// Utility function to print GroundValue for debugging
|
||||
inline void debug_print_ground_value(const GroundValue& v) {
|
||||
switch (v.type) {
|
||||
case GROUND_INT:
|
||||
std::cout << "INT: " << v.data.int_val << std::endl;
|
||||
break;
|
||||
case GROUND_DOUBLE:
|
||||
std::cout << "DOUBLE: " << v.data.double_val << std::endl;
|
||||
break;
|
||||
case GROUND_BOOL:
|
||||
std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl;
|
||||
break;
|
||||
case GROUND_STRING:
|
||||
std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl;
|
||||
break;
|
||||
case GROUND_CHAR:
|
||||
std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GROUND_LIB_H
|
52
extlibs/request/request.cpp
Normal file
52
extlibs/request/request.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "ground_lib.h"
|
||||
|
||||
#include <cpr/cpr.h>
|
||||
#include <cpr/interface.h>
|
||||
#include <fstream>
|
||||
|
||||
void error(std::string status) {
|
||||
std::cout << "Request error: " << status << std::endl;
|
||||
}
|
||||
|
||||
GroundValue simpleRequest(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_1(GROUND_STRING);
|
||||
|
||||
cpr::Response r = cpr::Get(cpr::Url(GET_STRING(args[0])));
|
||||
|
||||
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
||||
error("Non zero HTTP code " + std::to_string(r.status_code));
|
||||
return ground_string_val("Error code " + std::to_string(r.status_code));
|
||||
}
|
||||
|
||||
return ground_string_val(r.text);
|
||||
}
|
||||
|
||||
GroundValue saveContents(GroundValue* args, int arg_count) {
|
||||
VALIDATE_ARGS_2(GROUND_STRING, GROUND_STRING);
|
||||
|
||||
std::ofstream file(GET_STRING(args[1]), std::ios::binary);
|
||||
|
||||
if (file.good()) {
|
||||
cpr::Response r = cpr::Download(file, cpr::Url{GET_STRING(args[0])});
|
||||
|
||||
if (!(r.status_code >= 200 && r.status_code < 300)) {
|
||||
error("Non zero HTTP code " + std::to_string(r.status_code));
|
||||
return GROUND_BOOL_VAL(false);
|
||||
}
|
||||
} else {
|
||||
error(std::string("Cannot open file ") + GET_STRING(args[1]) + " for writing");
|
||||
return GROUND_BOOL_VAL(false);
|
||||
}
|
||||
|
||||
return GROUND_BOOL_VAL(true);
|
||||
}
|
||||
|
||||
GROUND_LIBRARY_INTERFACE()
|
||||
|
||||
GROUND_LIBRARY_INIT()
|
||||
REGISTER_GROUND_FUNCTION(simpleRequest);
|
||||
REGISTER_GROUND_FUNCTION(saveContents);
|
||||
GROUND_LIBRARY_INIT_END()
|
||||
|
||||
GROUND_LIBRARY_CLEANUP()
|
||||
GROUND_LIBRARY_CLEANUP_END()
|
1462
src/main.cpp
1462
src/main.cpp
File diff suppressed because it is too large
Load Diff
12
tests/args.grnd
Executable file
12
tests/args.grnd
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env ground
|
||||
stdlnout "Program args: "
|
||||
getlistsize *args &argsSize
|
||||
set &counter 0
|
||||
@loopstart
|
||||
equal $counter $argsSize &bool
|
||||
if $bool %end
|
||||
getlistat *args $counter &item
|
||||
stdlnout $item
|
||||
add 1 $counter &counter
|
||||
jump %loopstart
|
||||
@end
|
89
tests/everything.grnd
Normal file
89
tests/everything.grnd
Normal file
@@ -0,0 +1,89 @@
|
||||
# I/O
|
||||
|
||||
stdlnout "Hello there!"
|
||||
stdout "What is your name? "
|
||||
stdin &name
|
||||
add "Hello, " $name &out
|
||||
stdlnout $out
|
||||
|
||||
# Types
|
||||
stdlnout "dingus"
|
||||
stdlnout 7
|
||||
stdlnout 3.14159
|
||||
stdlnout true
|
||||
stdlnout 'e'
|
||||
|
||||
# Variables
|
||||
|
||||
set &testVar "This is a test"
|
||||
stdlnout $testVar
|
||||
|
||||
# Lists
|
||||
|
||||
setlist *testList "Item 1" "Another Item" "Item the Third"
|
||||
getlistat *testList 2 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
setlistat *testList 1 "I changed this item"
|
||||
getlistat *testList 1 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
listappend *testList "I appended this item"
|
||||
getlistat *testList 3 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
getlistsize *testList &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
# String Operations
|
||||
|
||||
set &testStr "dingus"
|
||||
|
||||
getstrsize $testStr &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
getstrcharat $testStr 3 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
# Maths
|
||||
|
||||
add 1 1 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
subtract 10 5 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
multiply 15 15 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
divide 36 4 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
# Comparisons
|
||||
|
||||
equal 5 5 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
inequal 5 5 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
greater 10 5 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
lesser 10 5 &tmp
|
||||
stdlnout $tmp
|
||||
|
||||
# Control flow
|
||||
|
||||
set &counter 0
|
||||
|
||||
@myLabel
|
||||
add $counter 1 &counter
|
||||
stdlnout $counter
|
||||
inequal $counter 10 &case
|
||||
if $case %myLabel
|
||||
|
||||
# That's it!
|
||||
|
||||
stdlnout "Everything ran! Check the output to see if it is what is expected."
|
||||
end 0
|
20
tests/exists.grnd
Normal file
20
tests/exists.grnd
Normal file
@@ -0,0 +1,20 @@
|
||||
set &testVar "dingus"
|
||||
exists &testVar &exist
|
||||
stdlnout $exist
|
||||
|
||||
setlist *myList "item"
|
||||
exists *myList &exist
|
||||
stdlnout $exist
|
||||
|
||||
@dingus
|
||||
exists %dingus &exist
|
||||
stdlnout $exist
|
||||
|
||||
exists &doesNotExist &exist
|
||||
stdlnout $exist
|
||||
|
||||
exists *doesNotExist &exist
|
||||
stdlnout $exist
|
||||
|
||||
exists %doesNotExist &exist
|
||||
stdlnout $exist
|
41
tests/functions.grnd
Normal file
41
tests/functions.grnd
Normal file
@@ -0,0 +1,41 @@
|
||||
fun -bool !jumpy
|
||||
stdlnout "This is the jumpy function"
|
||||
set &counter 0
|
||||
jump %inloop
|
||||
@jumpback
|
||||
stdlnout "Yay I jumped!"
|
||||
@inloop
|
||||
add 1 $counter &counter
|
||||
inequal 10 $counter &out
|
||||
stdout "Condition is"
|
||||
stdlnout $out
|
||||
if $out %jumpback
|
||||
stdlnout "Finished"
|
||||
return true
|
||||
endfun
|
||||
|
||||
call !jumpy &tmp
|
||||
|
||||
stdlnout "I called a function"
|
||||
|
||||
# This function returns a list
|
||||
|
||||
fun -list !dingus
|
||||
stdlnout "Testing lists in functions"
|
||||
setlist *dingle "heheheha" "hahahahe" "hmmm"
|
||||
return *dingle
|
||||
endfun
|
||||
|
||||
call !dingus *outlist
|
||||
|
||||
getlistsize *outlist &size
|
||||
set &counter 0
|
||||
@loopstart
|
||||
equal $size $counter &cond
|
||||
if $cond %loopend
|
||||
getlistat *outlist $counter &tmp
|
||||
stdlnout $tmp
|
||||
add 1 $counter &counter
|
||||
jump %loopstart
|
||||
@loopend
|
||||
end 0
|
5
tests/gettype.grnd
Normal file
5
tests/gettype.grnd
Normal file
@@ -0,0 +1,5 @@
|
||||
set &myVar "dingus"
|
||||
|
||||
gettype $myVar &type
|
||||
|
||||
stdlnout $type
|
@@ -1,7 +1,9 @@
|
||||
@begin
|
||||
stdout "Do you like cheese? "
|
||||
stdin &userin
|
||||
equal $userin "yes" &condition
|
||||
if $condition %7
|
||||
if $condition %end
|
||||
stdlnout "That is sad"
|
||||
jump %1
|
||||
jump %begin
|
||||
@end
|
||||
stdlnout "Awesome! I do too!"
|
||||
|
13
tests/lists.grnd
Normal file
13
tests/lists.grnd
Normal file
@@ -0,0 +1,13 @@
|
||||
# A cool list
|
||||
setlist *favWords "hello" "there" "general" "kenobi"
|
||||
|
||||
set &count 0
|
||||
set &passedThrough true
|
||||
|
||||
@jmpbck
|
||||
getlistat *favWords $count &tmp
|
||||
stdlnout $tmp
|
||||
add $count 1 &count
|
||||
getlistsize *favWords &tmp2
|
||||
inequal $count $tmp2 &tmp3
|
||||
if $tmp3 %jmpbck
|
10
tests/typeconvs.grnd
Normal file
10
tests/typeconvs.grnd
Normal file
@@ -0,0 +1,10 @@
|
||||
stod "3.14" &out
|
||||
stdlnout $out
|
||||
|
||||
stoi "732" &out
|
||||
add 1 $out &out
|
||||
stdlnout $out
|
||||
|
||||
tostring 3.14 &out
|
||||
add $out " is a number of sorts" &out
|
||||
stdlnout $out
|
3
tests/use/library.grnd
Normal file
3
tests/use/library.grnd
Normal file
@@ -0,0 +1,3 @@
|
||||
fun -string !dingus
|
||||
return "Hello from the library"
|
||||
endfun
|
5
tests/use/use.grnd
Normal file
5
tests/use/use.grnd
Normal file
@@ -0,0 +1,5 @@
|
||||
use "library"
|
||||
|
||||
call !library:dingus &var
|
||||
|
||||
stdlnout $var
|
Reference in New Issue
Block a user