Compare commits

...

18 Commits

Author SHA1 Message Date
Vaclav Tvrdik
17bdfdcbcb a bit od examples in doc 2022-12-29 14:13:56 +01:00
Vaclav Tvrdik
d9898aa64d fix erroneous paren 2022-09-12 16:05:08 +02:00
Vaclav Tvrdik
e7b62ab770 added comment for creating installation dirs 2022-09-12 16:04:48 +02:00
Vaclav Tvrdik
c9baa8a227 monterey homebrew directory change 2022-09-12 15:45:35 +02:00
vaclavt
a87ceb2f19 load_std_lib moved to anothep place in file 2022-06-16 17:08:58 +02:00
vaclavt
e6cf7aa636 doc::??? updates 2022-06-16 17:08:36 +02:00
vaclavt
7acab5d229 double is alias of float 2022-06-02 14:14:06 +02:00
vaclavt
25efdaac37 clear warning 2022-06-02 14:13:38 +02:00
vaclavt
8e6dff278d index scan is default on 2022-06-02 14:13:15 +02:00
vaclavt
1aa5fe3002 system catalogue initial version 2022-05-31 19:30:41 +02:00
vaclavt
8f60b11c25 vs code lisp changes 2022-05-31 19:29:23 +02:00
vaclavt
316bd953f4 fix for crash (weak strict ordering) 2022-05-31 19:28:56 +02:00
vaclavt
41bdeeda89 tabs instead of spaces 2022-05-31 19:27:53 +02:00
vaclavt
48a5d70cc4 small updates 2022-05-27 17:35:22 +02:00
vaclavt
fb552633c2 get-universal-time-ms added 2022-05-27 17:34:57 +02:00
vaclavt
8e142dc7ea until maco wip 2022-05-23 21:18:53 +02:00
vaclavt
fd8f3c6e06 Merge branch 'master' of http://gitea.stocksriddle.one/vaclavt/mlisp 2022-05-19 18:39:02 +02:00
vaclavt
6506494750 input2 added 2022-05-19 18:38:52 +02:00
26 changed files with 1374 additions and 108 deletions

View File

@@ -15,9 +15,9 @@ set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
# set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
include_directories(/usr/local/opt/openssl/include ${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR})
include_directories(/opt/homebrew/opt/openssl@1.1/include ${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR})
link_directories(/usr/local/lib /usr/local/opt/openssl/lib)
link_directories(/opt/homebrew/opt/openssl@1.1/lib)
project(ml)

View File

@@ -69,6 +69,7 @@ utils/local_install.sh
### TODO
- order of arguments in functions like member and filter - filter swap lambda and list
- add possibility to specify filename for input2 history file
- better output of !e in repl (resp !e !ee)
- unify -f and -run options
- add debug support, at least call stack

View File

@@ -0,0 +1,22 @@
(dotimes i 4 (print i) )
(def acc 0)
(print (dotimes i 4 (do (set! acc (+ acc i)) (print acc))) )
(defmacro until (cnd body)
(list 'while '(not (eval cnd))
body
))
(def stop nil)
(until stop
(do
(def line (input2 "=> "))
(if (= line "!q")
(set! stop #t)
(print line))
))

1082
doc/Doc.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
|option|Description|
|:-|-|
|-h|Prints help|
|-b|Skips loadin of std lib|
|-c code|Runs given code|
|-b|Skips loading of std lib|
|-c code|Runs passed code|
|-f source_file ..|Executes code in files|
|-run source_file ..|Executes code in file, if first line of file is sheebang, it is skipped|
|-i|Runs REPL|
@@ -23,7 +23,7 @@
## Syntax and Special Forms
|Special Form|Argument Evaluations|Purpose|Section|
|:-|-|-|-|
|`(if cond a b)`|`if` only evaluates its `cond` argument. If `cond` is truthy (non-zero), then `a` is evaluated. Otherwise, `b` is evaluated.|This special form is the main method of control flow.|Language|
|`(if cond a b)`|`if` only evaluates its `cond` argument. If `cond` is truthy, then `a` is evaluated. Otherwise, `b` is evaluated.|This special form is the main method of control flow.|Language|
|`(cond (test1 action1 ..) (test2 action2 ..) ... (testn ..))`|The first clause whose test evaluates to non-nil is selected; all other clauses are ignored, and the consequents of the selected clause are evaluated in order. If none of the test conditions are evaluated to be true, then the cond statement returns nil.|This special form is method of control flow.|Language|
|`(do a b c ...)`|`do` takes a list of s-expressions and evaluates them in the order they were given (in the current scope), and then returns the result of the last s-expression.|This special form allows lambda functions to have multi-step bodies.|Language|
|`(scope a b c ...)`|`scope` takes a list of s-expressions and evaluates them in the order they were given _in a new scope_, and then returns the result of the last s-expression.|This special form allows the user to evaluate blocks of code in new scopes.|Language|
@@ -39,8 +39,15 @@
|`(benchmark msg_string ...)`|`benchmark` takes a list of s-expressions and evaluates them in the order they were given (in the current scope), and then returns the result of the last s-expression and prints msg_string and timing info.||Language|
|`(set! x)`|`set!` ...|....|Language|
## Macros
|Signature|Description|Example|Section|
|:-|-|-|-|
|`(unles cond body)`|`unless` only evaluates its `cond` argument. If `cond` is not truthy, then `body` is evaluated.|`>>> (unless #t (print "it is #f")) => nil`|Language|
|`(dotimes v n body)`|Iterates over `v` from 0 below `n` and evaluated `body`. Returns the last value of v|`>>> (dotimes i 5 i) => 4`|Language|
|`(until cond body)`|Evaluated `body` as long as `cond` is not truthy|`>>> (def i 0)(until (> i 3) (set! i (inc i))) => 4`|Language|
## Library
|Signature|Description|Return values|Section|
|Signature|Description|Example|Section|
|:-|-|-|-|
|`(= a b)`|Test whether two values are equal|`1` when equal otherwise `nil`|Language|
|`(!= a b)`|Test whether two values are not equal|`1` when not equal otherwise `nil`|Language|
@@ -56,10 +63,10 @@
|`(list ..)`|Create a list of values||List manipulation|
|`(insert list index element)`|Insert an element into a list. Indexed from 0|new list with value inserted|List manipulation|
|`(index list index)`|Return element at index in list. First element is at index 0|Element at index|List manipulation|
|`(remove list index)`|Remove a value at an index from a list|List with element removed|List manipulation|
|`(len list)`|Get the length of a list|list length|List manipulation|
|`(push list element)`|Add an item to the end of a list|new list with element added|List manipulation|
|`(pop list)`|Returns last element of list|Last element|List manipulation|
|`(remove list index)`|Remove a value at an index from a list|`>>> (remove '(1 2 3 4) 1) => (1 3 4)`|List manipulation|
|`(len list)`|Get the length of a list|`>>> (len '(1 2 3 4)) => 4`|List manipulation|
|`(push list element)`|Add an item to the end of a list|`>>> (push '(1 2 3 4) 5) => (1 2 3 4 5)`|List manipulation|
|`(pop list)`|Returns last element of list|`>>> (pop '(1 2 3 4)) => 4`|List manipulation|
|`(head list)`|Returns first element of a list|`>>> (head '(1 2 3)) => 1`|List manipulation|
|`(tail list)`|Return all elements of list except first one|`>>> (tail '(1 2 3)) => (2 3)`|List manipulation|
|`(first list)`|Returns first element of a list|`>>> (first '(1 2 3)) => 1`|List manipulation|
@@ -83,6 +90,7 @@
|`(random low high)`|Get a random number between two numbers inclusively|`>>> (random 1 6) => 5`|System|
|`(include file)`|Read a file and execute its code||IO|
|`(input [prompt])`|Get user input with an optional prompt||IO|
|`(input2 [prompt])`|Get user input using libnoise with an optional prompt||IO|
|`(read)`|Reads in the printed representation of a Lisp object from input-stream, builds a corresponding Lisp object, and returns the object||IO|
|`(read-file filename)`|Get the contents of a file|`>>> (read-file "/tmp/a.txt") => "test"`|IO|
|`(read-file-lines filename lambda)`|Reads file and for each line call lambda with passing the line as a parameter|`(read-file-lines "/tmp/f.txt" (lambda (ln) (print ln))`|IO|
@@ -100,7 +108,8 @@
|`(parse-csv string)`|Parse CSV string|`>>> (parse-csv "A,B\n1,1\n2,2") => ((1 1) (2 2))`|String manipulation|
|`(parse-json json_string)`|Parse JSON string|`>>> (parse-json "{\"k1\":\"v1\", \"k2\":42, \"k3\":[\"a\",123,true,false,null]}") => (("k1" "v1") ("k2" 42) ("k3" ("a" 123 #t nil nil)))`|String manipulation|
|`(make-csv ..)`|Returns list as csv string|`>>> (make-csv '(("A" "B")(1 1)(2 2))) => "A,B\n1,1\n2,2"`|String manipulation|
|`(get-universal-time)`|Get current time as secs from epoch|`>>> (get-universal-time) => 1642152733`|Date and time|
|`(get-universal-time)`|Get current time as number of seconds from epoch|`>>> (get-universal-time) => 1642152733`|Date and time|
|`(get-universal-time-ms)`|Get current time as number of miliseconds from epoch|`>>> (get-universal-time-ms) => 1653575251097`|Date and time|
|`(get-localtime-offset)`|Offset in seconds between local time and gmt time|`>>> (get-localtime-offset) => 3600`|Date and time|
|`(date-to-str date format)`|Converts date to formated string. Format is strftime format (https://www.tutorialspoint.com/c_standard_library/c_function_strftime.htm)|`>>> (date-to-str (get-universal-time) "%Y-%m-%d %H:%M:%S") => "2021-03-13 19:53:01"`|Date and time|
|`(str-to-date string format)`|Converst string to time of secs since epoch. |`>>> (str-to-date "2021-03-13 19:53:01" "%Y-%m-%d %H:%M:%S") => 1615665181`|Date and time|
@@ -183,4 +192,4 @@
|`(thread-sleep milisecons)`|Sleeps thread for given amount of miliseconds|`>>> (thread-sleep 100) => 100`|Threading|
|`(threads-join)`|Wait for all running threads to finish||Threading|
|`(try block catch_block [finally_block])`|Evaluates block and if an exception is thrown, evaluates catch_block.Eventually in both cases evals finally_block. Return evaluated last expression from block if no exception or last expression from catch_block, if exception is thrown from block. Variable ml-exception in catch block is available with astring describing exception||Exceptions|
|`(throw exp_desc)`|Throws an exception with exp_desc describing what happened. exp_desc will be evaluated a returned as string|`>>> (throw (+ 1 2))\n3`|Exceptions|
|`(throw exp_desc)`|Throws an exception with exp_desc describing what happened. exp_desc will be evaluated a returned as string|`>>> (throw (+ 1 2))\n3`|Exceptions|

22
doc/readme.txt Normal file
View File

@@ -0,0 +1,22 @@
to convert Doc.md to Doc.html use https://markdowntohtml.com/ with custom ccs style
body {
color: black;
}
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid;
}
th {
text-align: left;
}
td {
height: 50px;
vertical-align: top;
}
code{
background: #0003;
color: #a31515;
}

57
ml.cpp
View File

@@ -1135,6 +1135,24 @@ MlValue input(std::vector<MlValue> args, MlEnvironment &env) {
return MlValue::string(s);
}
// Get user input with an optional prompt using line noise
MlValue input2(std::vector<MlValue> args, MlEnvironment &env) {
// TODO add setup etc
eval_args(args, env);
if (args.size() > 1)
throw MlError(MlValue("input2", input2), env, TOO_MANY_ARGS);
char *line = linenoise(args.empty() ? ">>> " : args[0].as_string().c_str());
if (line == nullptr) throw std::runtime_error("date_to_string, cannot initialise linenoise");
std::string input{line};
linenoise_add_to_history(input);
return MlValue::string(input);
}
// Get a random number between two numbers inclusively
MlValue random(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -1280,6 +1298,16 @@ MlValue get_universal_time(std::vector<MlValue> args, MlEnvironment &env) {
return MlValue(now());
}
// Get current time as miliseconds from epoch
MlValue get_universal_time_ms(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
if (!args.empty())
throw MlError(MlValue("get-universal-time-ms", get_universal_time_ms), env, TOO_MANY_ARGS);
return MlValue(now_ms());
}
// Get offsets in secs between local timezone and gmt
MlValue get_localtime_offset(std::vector<MlValue> args, MlEnvironment &env) {
eval_args(args, env);
@@ -2168,9 +2196,6 @@ MlValue usql(std::vector<MlValue> args, MlEnvironment &env) {
} // namespace builtin
void load_std_lib(MlEnvironment &env) {
run(STDLIB_LOADER, env);
}
// Does this environment, or its parent environment, have a variable?
bool MlEnvironment::has(const std::string &name) const {
@@ -2252,6 +2277,7 @@ std::map<const std::string, Builtin> builtin_funcs
std::make_pair("random", builtin::random),
std::make_pair("include", builtin::include),
std::make_pair("input", builtin::input),
std::make_pair("input2", builtin::input2),
std::make_pair("read", builtin::read),
std::make_pair("read-file", builtin::read_file),
std::make_pair("read-file-lines", builtin::read_file_lines),
@@ -2275,6 +2301,7 @@ std::map<const std::string, Builtin> builtin_funcs
// Datetime operations
std::make_pair("get-universal-time", builtin::get_universal_time),
std::make_pair("get-universal-time-ms", builtin::get_universal_time_ms),
std::make_pair("get-localtime-offset", builtin::get_localtime_offset),
std::make_pair("date-to-str", builtin::date_to_str),
std::make_pair("str-to-date", builtin::str_to_date),
@@ -2361,15 +2388,14 @@ void repl(MlEnvironment &env) {
MlValue tmp;
std::vector<MlValue> parsed;
setup_linenoise(env, builtin_funcs);
setup_linenoise_repl(env, builtin_funcs);
while (true) {
char *line = linenoise(">>> ");
if (line == nullptr) break;
linenoise_line_read(line);
input = std::string(line);
linenoise_add_to_history(input);
if (input == "!quit" || input == "!q")
break;
@@ -2393,8 +2419,6 @@ void repl(MlEnvironment &env) {
}
}
}
close_linenoise();
}
@@ -2413,6 +2437,12 @@ std::vector<std::string> getCmdOption(char *argv[], int argc, const std::string
return tokens;
}
void load_std_lib(MlEnvironment &env) {
run(STDLIB_LOADER, env);
}
int main(int argc, char *argv[]) {
MlEnvironment env;
std::vector<MlValue> args;
@@ -2425,11 +2455,13 @@ int main(int argc, char *argv[]) {
srand(time(NULL));
try {
// performance monitor on
if (cmdOptionExists(argv, argv + argc, "-p"))
if (cmdOptionExists(argv, argv + argc, "-p")) {
MlPerfMon::instance().turnOn();
}
// better stacktrace
if (cmdOptionExists(argv, argv + argc, "-d"))
if (cmdOptionExists(argv, argv + argc, "-d")) {
MlPerfMon::instance().debugOn();
}
// skip loading std lib
if (!cmdOptionExists(argv, argv + argc, "-b")) {
load_std_lib(env);
@@ -2444,6 +2476,9 @@ int main(int argc, char *argv[]) {
std::cout << VERSION << std::endl;
return 0;
}
setup_linenoise();
// passed code
if (cmdOptionExists(argv, argv + argc, "-c")) {
std::vector<std::string> codes = getCmdOption(argv, argc, "-c");
@@ -2467,6 +2502,8 @@ int main(int argc, char *argv[]) {
repl(env);
}
close_linenoise();
MlPerfMon::instance().print_results();
return 0;

View File

@@ -2,6 +2,7 @@
#include "ml_date.h"
#include <cstring>
#include <stdexcept>
#include <chrono>
long now() { // get-universal-time
time_t t = std::time(nullptr);
@@ -10,6 +11,13 @@ long now() { // get-universal-time
return now;
}
long now_ms() { // get-universal-time-ms
using namespace std::chrono;
milliseconds ms = duration_cast< milliseconds >(system_clock::now().time_since_epoch());
return ms.count();
}
long get_gmt_localtime_offset() {
std::time_t current_time;
std::time(&current_time);

View File

@@ -6,6 +6,7 @@
long now();
long now_ms();
long get_gmt_localtime_offset();

View File

@@ -79,7 +79,7 @@ void MlPerfMon::restore_callstack_position(size_t to_position) {
}
void MlPerfMon::clear_callstack() {
call_stack.empty();
auto r = call_stack.empty();
}
void MlPerfMon::print_results() const {

View File

@@ -1,13 +1,14 @@
#include "ml_util.h"
#include "string.h"
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
// #include <filesystem>
std::vector<std::string> commands {};
std::string history_file;
// kryplove z applu a jejich problemy s filesystemem
/*
@@ -20,8 +21,7 @@ std::string get_history_file_dir() {
}
*/
std::string get_history_file_dir() {
std::string file{"/.ml_history.txt"};
std::string get_history_filepath(const std::string &file) {
const char *t = std::getenv("HOME");
if (t == nullptr) return "/tmp/" + file;
@@ -30,33 +30,37 @@ std::string get_history_file_dir() {
MlEnvironment * repl_env = nullptr;
void setup_linenoise(const MlEnvironment &env, const std::map<const std::string, Builtin> &builtins) {
repl_env = (MlEnvironment*) &env;
std::string history_file = get_history_file_dir();
void setup_linenoise() {
history_file = get_history_filepath("/.ml_history.txt");
linenoiseHistoryLoad(history_file.c_str());
linenoiseHistorySetMaxLen(500);
linenoiseSetMultiLine(1);
}
void setup_linenoise_repl(const MlEnvironment &env, const std::map<const std::string, Builtin> &builtins) {
// basic linenoise setup must be already set
repl_env = (MlEnvironment*) &env;
linenoiseSetCompletionCallback(completion);
linenoiseSetHintsCallback(hints);
linenoiseSetMultiLine(1);
linenoiseHistoryLoad(history_file.c_str());
commands.reserve(builtins.size());
for(auto it = builtins.begin(); it != builtins.end(); ++it)
commands.push_back(it->first);
}
void linenoise_line_read(char *line) {
linenoiseHistoryAdd(line);
void linenoise_add_to_history(const std::string &line) {
if (!line.empty())
linenoiseHistoryAdd(line.c_str());
}
void close_linenoise() {
std::string history_file = get_history_file_dir();
linenoiseHistorySave(history_file.c_str());
}
size_t last_token_index( std::string str ) {
size_t last_token_index(std::string str) {
// remove trailing white space
while( !str.empty() && std::isspace( str.back() ) ) str.pop_back() ;

View File

@@ -1,11 +1,13 @@
#pragma once
#include "ml.h"
#include "linenoise.h"
void setup_linenoise(const MlEnvironment &env, const std::map<const std::string, Builtin> &builtins);
void linenoise_line_read(char *line);
#include <string>
void setup_linenoise();
void setup_linenoise_repl(const MlEnvironment &env, const std::map<const std::string, Builtin> &builtins);
void linenoise_add_to_history(const std::string &line);
void close_linenoise();

View File

@@ -43,6 +43,12 @@
nil
))
(defn doc::print-entry (entry)
(do (def call (doc::strip-backticks (second entry)))
(def desc (doc::strip-backticks (third entry)))
(print (term-red (first entry)) "-" (term-green (doc::strip-backticks (second entry))) "-" (third entry))
))
(defn doc::man (what)
(do (def man (filter (lambda (x) (= (first x) what)) doc::doc_entries))
(if man
@@ -75,29 +81,54 @@
(def sorted (quick-sort-by scores (lambda (a b) (< (first a) (first b)))))
(for e (take sorted 10)
(def entry (second e))
(def call (doc::strip-backticks (second entry)))
(def desc (doc::strip-backticks (third entry)))
(print (term-red (first entry)) "-" (term-green (doc::strip-backticks (second entry))) "-" (third entry))
)
(doc::print-entry (second e)))
(if (> (len sorted) 10) (print "..."))
))
(defn doc::section (what)
(do
(def entries '())
(for entry doc::doc_entries
; ("throw-exception" "`(throw-exception exp_desc)`" "Throws an exception with exp_desc describing what happened " "" "Exceptions"
; section matches
(if (= (string-downcase (fifth entry)) (string-downcase what))
(set! entries (push entries entry)))
)
(for e (quick-sort-by entries (lambda (a b) (> (string-cmp (first a) (first b)) 0)))
(doc::print-entry e))
))
(defn doc::all ()
(for e (quick-sort-by doc::doc_entries (lambda (a b) (> (string-cmp (first a) (first b)) 0)))
(doc::print-entry e))
)
(defn doc::appropos (which)
(doc::look which))
(defn doc::lookup (which)
(doc::look which))
;(defn doc::section (which)
; (print (term-red "implement me!")))
(defn doc::doc ()
(do
(print "Usage:")
(print "\t(doc::doc) - shows this help")
(print "\t(doc::man func) - func must be a string, ie (doc::man \"for\")")
(print "\t(doc::look str) - str must be a string, ie (doc::look \"length\")")
(print "\t(doc::lookup) - alias for doc::look")
(print "\t(doc::appropos) - alias for doc::look")
(print "\t(doc::all) - show short info about all functions")
(print "\t(doc::section sec) - show help for section, sec is string one of:")
(print "\t\t\t\t\"List manipulation\" \"Language\" \"System\"")
(print "\t\t\t\t\"String manipulation\" \"Date and time\" \"IO\" \"Regex\"")
(print "\t\t\t\t\"Type casting\" \"Threading\" \"Exceptions\"")
))
(def doc::doc_entries '()) ; must be here
; read doc into memory
(doc::read-doc-file "/usr/local/var/mlisp/Doc.md")
;;example
; (doc::man "first")
; (doc::look "string pad")
; (doc::look "list flat")

View File

@@ -78,6 +78,11 @@
body
))
(defmacro until (cnd body)
(list 'while '(not (eval cnd))
body
))
; return 1 when list contains item otherwise nil
(defn member (lst itm)

View File

@@ -9,11 +9,11 @@
(* n (fact (- n 1)))
))
; for scitej 4000 stack must be 16MB, otherwise 1000 is ok
(defn scitej (n)
; for adder 4000 stack must be 16MB, otherwise 1000 is ok
(defn adder (n)
(if (<= n 1)
1
(+ n (scitej (- n 1)))
(+ n (adder (- n 1)))
))
(write-file "/tmp/f.txt" "line 1\nline 2\nline3")
@@ -29,6 +29,11 @@
(thread-create (tcp-server 7778 (lambda (str) (list #t (+ "(print \"" (string-upcase str) "\")")))))
(ut::define-test "result of (unless #t (print \"#f\"))" '(ut::assert-false (unless #t (print "#f"))))
(ut::define-test "result of (dotimes i 5 i)" '(ut::assert-equal 4 (dotimes i 5 i)))
(ut::define-test "result of (def i 0)(until (> i 3) (set! i (inc i)))" '(ut::assert-equal 4 (do (def i 0)(until (> i 3) (set! i (inc i))))))
(ut::define-test "result of (and (> 2 1) (> 2 1))" '(ut::assert-true (and (> 2 1) (> 2 1))))
(ut::define-test "result of (or (> 2 1) (> 2 1))" '(ut::assert-true (or (> 2 1) (> 2 1))))
(ut::define-test "retult of (and (> 2 1) (> 1 2))" '(ut::assert-false (and (> 2 1) (> 1 2))))
@@ -57,7 +62,7 @@
(ut::define-test "result of (range 1.5 5.5)" '(ut::assert-equal '(1.500000 2.500000 3.500000 4.500000) (range 1.5 5.5)))
(ut::define-test "result of (fact 5)" '(ut::assert-equal 120 (fact 5)))
(ut::define-test "result of (scitej 1000)" '(ut::assert-equal 500500 (scitej 1000)))
(ut::define-test "result of (adder 1000)" '(ut::assert-equal 500500 (adder 1000)))
(ut::define-test "result of (len json_list)" '(ut::assert-equal 3 (len json_list)))

View File

@@ -162,7 +162,7 @@ TokenType Lexer::type(const std::string &token) {
if (token == "not") return TokenType::keyword_not;
if (token == "null") return TokenType::keyword_null;
if (token == "integer") return TokenType::keyword_integer;
if (token == "float") return TokenType::keyword_float;
if (token == "float" || token == "double") return TokenType::keyword_float;
if (token == "varchar") return TokenType::keyword_varchar;
if (token == "date") return TokenType::keyword_date;
if (token == "boolean") return TokenType::keyword_bool;

View File

@@ -385,19 +385,18 @@ namespace usql {
std::unique_ptr<Node> Parser::parse_where_clause() {
if (m_lexer.tokenType() != TokenType::keyword_where) {
return std::make_unique<TrueNode>();
}
if (m_lexer.tokenType() != TokenType::keyword_where) {
return std::make_unique<TrueNode>();
}
m_lexer.skipToken(TokenType::keyword_where);
m_lexer.skipToken(TokenType::keyword_where);
std::unique_ptr<Node> left = parse_expression();
do {
left = parse_expression(std::move(left));
} while (m_lexer.tokenType() != TokenType::eof && m_lexer.tokenType() != TokenType::keyword_order && m_lexer.tokenType() != TokenType::keyword_offset && m_lexer.tokenType() != TokenType::keyword_limit);
std::unique_ptr<Node> left = parse_expression();
do {
left = parse_expression(std::move(left));
} while (m_lexer.tokenType() != TokenType::eof && m_lexer.tokenType() != TokenType::keyword_order && m_lexer.tokenType() != TokenType::keyword_offset && m_lexer.tokenType() != TokenType::keyword_limit && m_lexer.tokenType() != TokenType::semicolon);
return left;
return left;
}
std::unique_ptr<Node> Parser::parse_expression() {

View File

@@ -175,9 +175,6 @@ struct FunctionNode : Node {
};
Type function;
std::vector<std::unique_ptr<Node>> params;
FunctionNode(std::string func_name, std::vector<std::unique_ptr<Node>> pars) :
Node(NodeType::function), function(get_function(func_name)), params(std::move(pars)) {}
@@ -199,6 +196,9 @@ struct FunctionNode : Node {
}
std::cout << ")" << std::endl;
}
Type function;
std::vector<std::unique_ptr<Node>> params;
};
struct TrueNode : Node {
@@ -581,7 +581,6 @@ struct CreateIndexNode : Node {
};
class Parser {
private:
public:
Parser();

View File

@@ -171,7 +171,7 @@ public:
case 5:
return (ColValue &) *std::get_if<ColBooleanValue>(&m_columns[i]);
default:
throw Exception("should not happen");
throw Exception("ColValue &operator[](int i), type index invalid :" + std::to_string(type_index));
}
}

View File

@@ -12,7 +12,7 @@ std::vector<std::pair<std::string, std::string>> Settings::m_settings =
std::make_pair("BOOL_TRUE_LITERAL", "Y"),
std::make_pair("BOOL_FALSE_LITERAL", "N"),
std::make_pair("DOUBLE_FORMAT", "%.2f"),
std::make_pair("USE_INDEXSCAN", "N"),
std::make_pair("USE_INDEXSCAN", "Y"),
std::make_pair("MAX_PARALLELISM", "1") }; // values "AUTO" or number of workers; when number negative means std::thread::hardware_concurrency() - number

View File

@@ -6,9 +6,36 @@
namespace usql {
USql::USql() {
// create catalogue tables first
std::vector<std::string> k_debug_sql_commands {
"create table usql_tables(name varchar(32) not null, modified boolean not null)",
"create table usql_columns(table_name varchar(32) not null, column_name varchar(32) not null, column_type varchar(16) not null, column_length integer not null, nullable boolean not null, column_order integer not null)"
};
// create cataloque tables
for (const auto &command : k_debug_sql_commands) {
std::unique_ptr<Node> create_table_node = m_parser.parse(command);
const CreateTableNode &node = static_cast<CreateTableNode &>(*create_table_node);
Table table{node.table_name, node.cols_defs};
m_tables.push_back(table);
}
// insert data into cataloque tables
for (const auto &command : k_debug_sql_commands) {
std::unique_ptr<Node> create_table_node = m_parser.parse(command);
const CreateTableNode &node = static_cast<CreateTableNode &>(*create_table_node);
execute_create_table_sys_catalogue(node);
}
}
std::unique_ptr<Table> USql::execute(const std::string &command) {
try {
std::unique_ptr<Node> node = m_parser.parse(command);
// node->dump();
return execute(*node);
} catch (const std::exception &e) {

View File

@@ -11,16 +11,16 @@
namespace usql {
class USql {
public:
USql() = default;
USql();
std::unique_ptr<Table> execute(const std::string &command);
private:
std::unique_ptr<Table> execute(Node &node);
std::unique_ptr<Table> execute_create_table(const CreateTableNode &node);
bool execute_create_table_sys_catalogue(const CreateTableNode &node);
std::unique_ptr<Table> execute_create_index(const CreateIndexNode &node);
std::unique_ptr<Table> execute_create_table_as_table(const CreateTableAsSelectNode &node);
std::unique_ptr<Table> execute_load(const LoadIntoTableNode &node);
@@ -59,9 +59,6 @@ private:
void check_index_not_exists(const std::string &index_name);
private:
Parser m_parser;
std::list<Table> m_tables;
static void execute_distinct(SelectFromTableNode &node, Table *result);
static void execute_order_by(SelectFromTableNode &node, Table *result);
static void execute_offset_limit(OffsetLimitNode &node, Table *result);
@@ -97,6 +94,11 @@ private:
bool normalize_where(const Node *node) const;
Table::rows_scanner get_iterator(Table *table, const Node *where) const;
private:
Parser m_parser;
std::list<Table> m_tables;
};

View File

@@ -15,10 +15,35 @@ std::unique_ptr<Table> USql::execute_create_table(const CreateTableNode &node) {
Table table{node.table_name, node.cols_defs};
m_tables.push_back(table);
execute_create_table_sys_catalogue(node);
return create_stmt_result_table(0, "table created", 0);
}
bool USql::execute_create_table_sys_catalogue(const CreateTableNode &node) {
// usql_tables
auto r = execute("insert into usql_tables(name, modified) values('" + node.table_name + "', false)");
// usql_columns
for(const ColDefNode & col_def : node.cols_defs) {
std::string i {"insert into usql_columns(table_name, column_name, column_type, column_length, nullable, column_order) values("};
i += "'" + node.table_name + "', ";
i += "'" + col_def.name + "', ";
i += "'" + column_type_name(col_def.type) + "', ";
i += std::to_string(col_def.length) + ", ";
i += (col_def.null ? "true, " : "false, ");
i += std::to_string(col_def.order);
i += ")";
auto r = execute(i);
// r->print();
}
return true;
}
std::unique_ptr<Table> USql::execute_create_index(const CreateIndexNode &node) {
Table *table_def = find_table(node.table_name); // throws exception if not found
ColDefNode col_def = table_def->get_column_def(node.column_name); // throws exception if not found
@@ -57,7 +82,6 @@ std::unique_ptr<Table> USql::execute_create_table_as_table(const CreateTableAsSe
}
std::unique_ptr<Table> USql::execute_drop(const DropTableNode &node) {
auto name_cmp = [node](const Table& t) { return t.m_name == node.table_name; };
@@ -70,11 +94,13 @@ std::unique_ptr<Table> USql::execute_drop(const DropTableNode &node) {
throw Exception("table not found (" + node.table_name + ")");
}
std::unique_ptr<Table> USql::execute_set(const SetNode &node) {
Settings::set_setting(node.name, node.value);
return create_stmt_result_table(0, "set succeeded", 1);
}
std::unique_ptr<Table> USql::execute_show(const ShowNode &node) {
std::string value = Settings::get_setting(node.name);
return create_stmt_result_table(0, "show succeeded: " + value, 1);

View File

@@ -35,7 +35,7 @@ std::pair<bool, std::vector<rowid_t>> USql::look_for_usable_index(const Node *wh
if (used_index != nullptr) {
std::vector<rowid_t> rowids = used_index->search((ValueNode *)ron->right.get());
#ifndef NDEBUG
std::cout << "using index " << table->m_name << "(" << used_index->get_column_name() << "), " << rowids.size() << "/" << table->rows_count() << std::endl;
std::cerr << "using index " << table->m_name << "(" << used_index->get_column_name() << "), " << rowids.size() << "/" << table->rows_count() << std::endl;
#endif
return std::make_pair(true, rowids);
}
@@ -155,8 +155,7 @@ void USql::setup_order_columns(std::vector<ColOrderNode> &node, Table *table) {
void USql::execute_distinct(SelectFromTableNode &node, Table *result) {
if (!node.distinct) return;
auto compare_rows = [](const Row &a, const Row &b) { return a.compare(b) >= 0; };
std::sort(result->m_rows.begin(), result->m_rows.end(), compare_rows);
std::sort(result->m_rows.begin(), result->m_rows.end(), [](const Row &a, const Row &b) { return a.compare(b) > 0; });
result->m_rows.erase(std::unique(result->m_rows.begin(), result->m_rows.end()), result->m_rows.end());
}

View File

@@ -55,29 +55,6 @@
<key>name</key>
<string>meta.function.lisp</string>
</dict>
<!-- <dict>
<key>match</key>
<string>(?<=\s)(?i:&allow-other-keys|&aux|&body|&environment|&key|&optional|&rest|&whole)(?=\s+)</string>
<key>name</key>
<string>meta.function-parameters.lisp</string>
</dict> -->
<!-- <dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>storage.type.function-type.lisp</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>entity.name.type.lisp</string>
</dict>
</dict>
<key>match</key>
<string>(?:\()((?i:deftype|defstruct|define-condition|defpackage|defclass))\s+((?:\w|[+\-<>/*&amp;=.?!$%:@\[\]^{}~#|])+)</string>
</dict> -->
<dict>
<key>captures</key>
<dict>

View File

@@ -8,19 +8,27 @@ echo "building ml"
cmake --build ./ --target all -j 4 --
echo ""
# echo "create dirs"
# sudo mkdir -p /usr/local/var/mlisp/
# sudo mkdir -p /usr/local/bin/
# sudo chown -R vaclavt:admin /usr/local/bin/
# sudo chown -R vaclavt:admin /usr/local/var/mlisp/
echo "copying lsp files"
mkdir -p /usr/local/var/mlisp/
cp stdlib/*.lsp /usr/local/var/mlisp/
echo "copying doc files"
cp doc/*.md /usr/local/var/mlisp/
echo "copying ml file"
mv ./ml /usr/local/bin/ml
echo ""
echo "if syntax has changed you may use"
echo "cp utils/Lisp.tmLanguage ~/.vscode/extensions/mattn.lisp-0.1.12/syntaxes/"
# echo "or"
# echo "cp utils/Lisp.tmLanguage ~/.local/share/code-server/extensions/mattn.lisp-0.1.11/syntaxes/Lisp.tmLanguage"
echo "or"
echo "cp utils/Lisp.tmLanguage ~/.local/share/code-server/extensions/mattn.lisp-0.1.11/syntaxes/Lisp.tmLanguage"
echo ""
ml -v