doc update
This commit is contained in:
parent
defc628204
commit
364d83b199
@ -1,6 +1,10 @@
|
||||
Output Buffer Functions
|
||||
Output / Invocation Functions
|
||||
|
||||
call_file
|
||||
load
|
||||
ob_clear
|
||||
ob_get
|
||||
ob_get_clear
|
||||
ob_start
|
||||
print
|
||||
render_file
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
String Functions
|
||||
|
||||
concat
|
||||
filter
|
||||
first
|
||||
join
|
||||
nibble
|
||||
print
|
||||
split
|
||||
split_space
|
||||
split_utf8
|
||||
|
||||
@ -11,7 +11,7 @@ void render_see_section(String name)
|
||||
}
|
||||
else if(line != "")
|
||||
{
|
||||
<><li><a href="index.uce?p=<?= line ?>"><?= line ?><span style="opacity:0.5">()</span></a></li></>
|
||||
<><li><a href="index.uce?p=<?= uri_encode(line) ?>"><?= line ?><span style="opacity:0.5">()</span></a></li></>
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
23
doc/pages/call_file.txt
Normal file
23
doc/pages/call_file.txt
Normal file
@ -0,0 +1,23 @@
|
||||
:sig
|
||||
DTree* call_file(String file_name, String function_name, DTree* call_param = null)
|
||||
|
||||
:params
|
||||
file_name : UCE file to load and execute
|
||||
function_name : name of the function to invoke
|
||||
call_param : optional, call parameter
|
||||
return value : DTree* returned from function
|
||||
|
||||
:desc
|
||||
Calls a function inside a UCE file.
|
||||
|
||||
:Example
|
||||
// export a function
|
||||
EXPORT void test_func()
|
||||
{
|
||||
print("HELLO FROM TEST FUNCTION");
|
||||
}
|
||||
// use that function in another file
|
||||
call_file("call_file_funcs.uce", "test_func");
|
||||
|
||||
:see
|
||||
>ob
|
||||
11
doc/pages/concat.txt
Normal file
11
doc/pages/concat.txt
Normal file
@ -0,0 +1,11 @@
|
||||
:sig
|
||||
String concat(...vals)
|
||||
|
||||
:params
|
||||
...val : one or more values that should be concatenated
|
||||
|
||||
:desc
|
||||
Returns a string with all the parameters concatenated into one.
|
||||
|
||||
:see
|
||||
>string
|
||||
@ -7,3 +7,5 @@ file name : name of an UCE file that should be included
|
||||
:desc
|
||||
Includes another UCE file
|
||||
|
||||
:see
|
||||
>ob
|
||||
@ -7,4 +7,5 @@ void print(...val)
|
||||
:desc
|
||||
Appends data to the current request's output stream.
|
||||
|
||||
|
||||
:see
|
||||
>string
|
||||
|
||||
16
doc/pages/render_file.txt
Normal file
16
doc/pages/render_file.txt
Normal file
@ -0,0 +1,16 @@
|
||||
:sig
|
||||
void render_file(String file_name, DTree& call_param = null)
|
||||
|
||||
:params
|
||||
file_name : UCE file to load and execute
|
||||
call_param : optional, call parameter
|
||||
|
||||
:desc
|
||||
Calls another UCE file and executes its RENDER() function.
|
||||
|
||||
:Example
|
||||
// call a common page template
|
||||
render_file("page-template.uce");
|
||||
|
||||
:see
|
||||
>ob
|
||||
142
doc/singlepage.uce
Normal file
142
doc/singlepage.uce
Normal file
@ -0,0 +1,142 @@
|
||||
StringMap* already_shown_items;
|
||||
|
||||
void render_doc_page(String page)
|
||||
{
|
||||
(*already_shown_items)[page] = "Y";
|
||||
auto doc = split(file_get_contents("pages/"+page+".txt"), "\n");
|
||||
String layout_class = "text";
|
||||
u32 line_idx = 0;
|
||||
for(auto s : doc)
|
||||
{
|
||||
line_idx++;
|
||||
if(s == "")
|
||||
{
|
||||
|
||||
}
|
||||
else if(s.substr(0, 1) == ":")
|
||||
{
|
||||
layout_class = s.substr(1);
|
||||
if(line_idx > 1)
|
||||
{
|
||||
<></div></>
|
||||
}
|
||||
<><div class="<?= layout_class ?>"></>
|
||||
if(layout_class == "params")
|
||||
{
|
||||
<><h3>Parameters</h3></>
|
||||
}
|
||||
else if(layout_class == "sig")
|
||||
{
|
||||
String page_name = page;
|
||||
if(page[1] == '_')
|
||||
{
|
||||
nibble(page_name, "_");
|
||||
}
|
||||
<><h2><?= page_name ?></h2></>
|
||||
}
|
||||
else if(layout_class == "pre")
|
||||
{
|
||||
layout_class = "sig";
|
||||
}
|
||||
else if(layout_class == "desc")
|
||||
{
|
||||
<><h3>Description</h3></>
|
||||
}
|
||||
else if(layout_class == "see")
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
<><h3><?= layout_class ?></h3></>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(s.substr(0, 1) == "-")
|
||||
{
|
||||
nibble(s, "-");
|
||||
<><li><?= (s) ?></li></>
|
||||
}
|
||||
else if(layout_class == "sig")
|
||||
{
|
||||
<><pre><? print(s); ?></pre></>
|
||||
}
|
||||
else if(layout_class == "params")
|
||||
{
|
||||
<><div><b><?= trim(nibble(s, ":")) ?></b> : <?= trim(s) ?></div></>
|
||||
}
|
||||
else if(layout_class == "see")
|
||||
{
|
||||
if(s[0] == '>')
|
||||
{
|
||||
//render_see_section(s.substr(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
<><div><a href="index.uce?p=<?= trim(s) ?>"><?= trim(s) ?><span style="opacity:0.5">()</span></a></div></>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<><div><? print(s); ?></div></>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render_see_section(String name)
|
||||
{
|
||||
StringList lines = split(file_get_contents("areas/"+name+".txt"), "\n");
|
||||
s32 idx = 0;
|
||||
for(auto line : lines)
|
||||
{
|
||||
if(idx == 0)
|
||||
{
|
||||
<><h1><?= line ?></h1></>
|
||||
}
|
||||
else if(line != "")
|
||||
{
|
||||
render_doc_page(line);
|
||||
}
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RENDER()
|
||||
{
|
||||
|
||||
already_shown_items = new StringMap();
|
||||
|
||||
String page = first(context->get["p"], "index");
|
||||
|
||||
<><html>
|
||||
<head>
|
||||
<!--<link rel="stylesheet" href='style.css?v=<?= time() ?>'></link>-->
|
||||
</head>
|
||||
<body>
|
||||
<h1>
|
||||
UCE API
|
||||
</h1>
|
||||
<?
|
||||
|
||||
for(auto file_name : ls("areas/"))
|
||||
{
|
||||
String ft = nibble(file_name, ".");
|
||||
render_see_section(ft);
|
||||
}
|
||||
|
||||
?><h1>Other Functions and Data Structures</h1><?
|
||||
for(auto file_name : ls("pages/"))
|
||||
{
|
||||
String ft = nibble(file_name, ".");
|
||||
if((*already_shown_items)[ft] == "")
|
||||
render_doc_page(ft);
|
||||
}
|
||||
|
||||
?>
|
||||
</body>
|
||||
</html></>
|
||||
|
||||
}
|
||||
@ -159,20 +159,16 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
pc.append("#include \"" + sub_su->bin_path + "/" + sub_su->pre_file_name + "\"\n");
|
||||
}
|
||||
}
|
||||
else if(false && current_line.substr(0, 6) == "EXPORT" && isspace(current_line[6]))
|
||||
else if(current_line.substr(0, 6) == "EXPORT" && isspace(current_line[6]))
|
||||
{
|
||||
current_line = "";
|
||||
auto end_declaration_pos = content.find("{", i);
|
||||
if(end_declaration_pos != std::string::npos)
|
||||
{
|
||||
// remove string "API " from output
|
||||
//pc.resize(pc.length() - 7);
|
||||
pc.append(1, '\n');
|
||||
String declaration = trim(content.substr(i, end_declaration_pos - i));
|
||||
String return_type_and_name = nibble(declaration, "(");
|
||||
StringList rtn_list = split_space(return_type_and_name);
|
||||
String fn_name = rtn_list.back(); rtn_list.pop_back();
|
||||
su->api_declarations.push_back(fn_name + ":" + join(rtn_list, " ") + ":(" + declaration + "\n");
|
||||
printf("declaration found: %s\n", declaration.c_str());
|
||||
su->api_declarations.push_back(declaration+";\n");
|
||||
//printf("declaration found: %s\n", declaration.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -430,7 +426,20 @@ void render_file(String file_name, DTree& call_param)
|
||||
compiler_invoke(context, file_name, call_param);
|
||||
}
|
||||
|
||||
DTree* call_file_function(String file_name, String function_name, DTree* call_param)
|
||||
SharedUnit* load_file(String file_name)
|
||||
{
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(su && su->so_handle)
|
||||
{
|
||||
return(su);
|
||||
}
|
||||
else
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
DTree* call_file(String file_name, String function_name, DTree* call_param)
|
||||
{
|
||||
DTree* result;
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
@ -445,7 +454,7 @@ DTree* call_file_function(String file_name, String function_name, DTree* call_pa
|
||||
auto f = (dtree_call_handler)dlsym(su->so_handle, function_name.c_str());
|
||||
if(!f)
|
||||
{
|
||||
print("Error: call_file_function() function '", function_name, "' not found");
|
||||
print("Error: call_file() function '", function_name, "' not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -459,7 +468,7 @@ DTree* call_file_function(String file_name, String function_name, DTree* call_pa
|
||||
}
|
||||
else
|
||||
{
|
||||
print("Error: call_file_function() could not load unit file '", file_name, "'");
|
||||
print("Error: call_file() could not load unit file '", file_name, "'");
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
@ -10,8 +10,9 @@ SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_opti
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param);
|
||||
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional = false);
|
||||
|
||||
SharedUnit* load_file(String file_name);
|
||||
void render_file(String file_name);
|
||||
void render_file(String file_name, DTree& call_param);
|
||||
DTree* call_file_function(String file_name, String function_name, DTree* call_param = 0);
|
||||
DTree* call_file(String file_name, String function_name, DTree* call_param = 0);
|
||||
|
||||
StringList precompile_jobs;
|
||||
|
||||
@ -43,7 +43,7 @@ String operator+(String lhs, f32 rhs) {
|
||||
}
|
||||
|
||||
#define DEBUG_MEMORY_OFF
|
||||
#define GLOBAL_ARENA_ALLOCATOR
|
||||
#define NO_GLOBAL_ARENA_ALLOCATOR
|
||||
|
||||
struct MemoryArena {
|
||||
|
||||
@ -293,3 +293,11 @@ void print(Ts... args)
|
||||
((*context->ob << args), ...);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
String concat(Ts... args)
|
||||
{
|
||||
std::stringstream out;
|
||||
((out << args), ...);
|
||||
return(out.str());
|
||||
}
|
||||
|
||||
|
||||
21
test/call_file.uce
Normal file
21
test/call_file.uce
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
RENDER()
|
||||
{
|
||||
|
||||
<>
|
||||
<link rel="stylesheet" href='style.css'></link>
|
||||
<h1>
|
||||
<a href="index.uce">UCE Test</a>:
|
||||
call_file()
|
||||
</h1>
|
||||
<pre><?
|
||||
call_file("call_file_funcs.uce", "test_func");
|
||||
print("\n");
|
||||
render_file("call_file_funcs.uce");
|
||||
?></pre>
|
||||
<pre><?= var_dump(context->params) ?></pre>
|
||||
</>
|
||||
|
||||
}
|
||||
|
||||
6
test/call_file_funcs.uce
Normal file
6
test/call_file_funcs.uce
Normal file
@ -0,0 +1,6 @@
|
||||
// some bullshit?
|
||||
|
||||
EXPORT void test_func()
|
||||
{
|
||||
print("HELLO FROM TEST FUNCTION");
|
||||
}
|
||||
@ -31,6 +31,7 @@ RENDER()
|
||||
<li><a href="random.uce">RNG/Noise</a></li>
|
||||
<li><a href="task.uce">Task API</a></li>
|
||||
<li><a href="utf8.uce">UTF-8</a></li>
|
||||
<li><a href="call_file.uce">call_file()</a></li>
|
||||
</ul>
|
||||
<pre><?
|
||||
print("Worker PID: ", my_pid, "\n");
|
||||
|
||||
6
test/script-example1.usp
Normal file
6
test/script-example1.usp
Normal file
@ -0,0 +1,6 @@
|
||||
v1 : string = "";
|
||||
|
||||
v2 = 'BLA';
|
||||
|
||||
for(v3 => c);
|
||||
print(c);
|
||||
317
test/script.uce
317
test/script.uce
@ -1,4 +1,18 @@
|
||||
|
||||
String add_token_type(String tokenstr)
|
||||
{
|
||||
char c = tokenstr[0];
|
||||
if(c == 34) // quote character, as number here because of HTML parser bug
|
||||
return(String("Q") + tokenstr);
|
||||
if(isalpha(c))
|
||||
return(String("I") + tokenstr);
|
||||
if(isdigit(c))
|
||||
return(String("N") + tokenstr);
|
||||
if(ispunct(c))
|
||||
return(String("O") + tokenstr);
|
||||
return(String("?") + tokenstr);
|
||||
}
|
||||
|
||||
StringList script_tokenize(String code)
|
||||
{
|
||||
StringList result;
|
||||
@ -17,7 +31,7 @@ StringList script_tokenize(String code)
|
||||
else if(quote_character == c && last_character != '\\')
|
||||
{
|
||||
mode = 'N';
|
||||
result.push_back(current_token);
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
}
|
||||
else
|
||||
@ -30,7 +44,7 @@ StringList script_tokenize(String code)
|
||||
if(isspace(c))
|
||||
{
|
||||
if(current_token != "")
|
||||
result.push_back(current_token);
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
}
|
||||
else if(c == '"' || c == '\'')
|
||||
@ -38,15 +52,15 @@ StringList script_tokenize(String code)
|
||||
mode = 'Q';
|
||||
quote_character = c;
|
||||
if(current_token != "")
|
||||
result.push_back(current_token);
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "\"";
|
||||
}
|
||||
else if(ispunct(c) && c != '_')
|
||||
{
|
||||
if(current_token != "")
|
||||
result.push_back(current_token);
|
||||
result.push_back(add_token_type(current_token));
|
||||
current_token = "";
|
||||
result.push_back(String().append(1, c));
|
||||
result.push_back(add_token_type(String("").append(1, c)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -56,7 +70,7 @@ StringList script_tokenize(String code)
|
||||
last_character = c;
|
||||
}
|
||||
if(current_token != "")
|
||||
result.push_back(current_token);
|
||||
result.push_back(add_token_type(current_token));
|
||||
return(result);
|
||||
}
|
||||
|
||||
@ -64,40 +78,37 @@ struct ASTNode
|
||||
{
|
||||
String identifier = "";
|
||||
String type_name = "";
|
||||
String string_literal = "";
|
||||
char type = 0;
|
||||
ASTNode* assign = 0;
|
||||
ASTNode* call_params = 0;
|
||||
ASTNode* children = 0;
|
||||
ASTNode* next = 0;
|
||||
std::vector<ASTNode*> assign;
|
||||
std::vector<ASTNode*> call_params;
|
||||
std::vector<ASTNode*> children;
|
||||
|
||||
ASTNode(char _type)
|
||||
{
|
||||
type = _type;
|
||||
type_name = "";
|
||||
identifier = "";
|
||||
assign = 0;
|
||||
children = 0;
|
||||
next = 0;
|
||||
type_name = "";
|
||||
string_literal = "";
|
||||
type = _type;
|
||||
}
|
||||
|
||||
String to_string(String indent = "")
|
||||
{
|
||||
String result = "";
|
||||
ASTNode* current = this;
|
||||
while(current)
|
||||
{
|
||||
result += indent + String().append(1, current->type);
|
||||
if(identifier != "") result += " ident=" + identifier;
|
||||
if(type_name != "") result += " type=" + type_name;
|
||||
result += "\n";
|
||||
if(current->call_params)
|
||||
result += current->call_params->to_string(indent + "--CALL ");
|
||||
if(current->assign)
|
||||
result += current->assign->to_string(indent + "--ASSIGN ");
|
||||
if(current->children)
|
||||
result += current->children->to_string(indent + " ");
|
||||
current = current->next;
|
||||
}
|
||||
result += indent + String().append(1, type);
|
||||
if(identifier != "")
|
||||
result += " ident=" + identifier;
|
||||
if(type_name != "")
|
||||
result += " type_name=" + type_name;
|
||||
if(string_literal != "")
|
||||
result += " " + string_literal;
|
||||
result += "\n";
|
||||
for(auto callp : call_params)
|
||||
result += indent + " CALLP " + callp->to_string(indent + " ");
|
||||
for(auto assign_expr : assign)
|
||||
result += indent + " ASSIGN VALUE " + assign_expr->to_string(indent + " ");
|
||||
for(auto child : children)
|
||||
result += indent + " " + child->to_string(indent + " ");
|
||||
return(result);
|
||||
}
|
||||
|
||||
@ -106,99 +117,200 @@ struct ASTNode
|
||||
struct ParserState
|
||||
{
|
||||
|
||||
ASTNode* root = 0;
|
||||
ASTNode* root;
|
||||
StringList tokens;
|
||||
s32 token_index = 0;
|
||||
String error = "";
|
||||
u64 error_location = 0;
|
||||
|
||||
String next()
|
||||
String consume(char token_kind = 0)
|
||||
{
|
||||
return(tokens[token_index++]);
|
||||
if(error_location > 0) return("");
|
||||
if(token_kind && look_ahead(0)[0] != token_kind)
|
||||
{
|
||||
unexpected_token();
|
||||
}
|
||||
printf("consume #%i %s -> %s \n", token_index, look_ahead(0).c_str(), look_ahead(1).c_str());
|
||||
String tk = look_ahead(0);
|
||||
token_index++;
|
||||
return(tk);
|
||||
}
|
||||
|
||||
String look_ahead(u32 by)
|
||||
String look_ahead(s32 by)
|
||||
{
|
||||
if(error_location > 0)
|
||||
return("_");
|
||||
if(token_index+by < 0 || token_index+by >= tokens.size())
|
||||
return("_");
|
||||
return(tokens[token_index+by]);
|
||||
}
|
||||
|
||||
bool expect(String token_str)
|
||||
bool more()
|
||||
{
|
||||
String found = look_ahead(0);
|
||||
if(found == token_str)
|
||||
return(true);
|
||||
token_index = tokens.size() + 1;
|
||||
error = String("'") + token_str + "' expected but '" + found + "' found";
|
||||
return(false);
|
||||
if(error_location > 0)
|
||||
return(false);
|
||||
return(token_index < tokens.size());
|
||||
}
|
||||
|
||||
void consume(String token_str)
|
||||
void unexpected_token(s32 offset = 0)
|
||||
{
|
||||
if(expect(token_str))
|
||||
next();
|
||||
if(error_location) return;
|
||||
String found = look_ahead(offset);
|
||||
error_location = token_index;
|
||||
token_index = tokens.size() + 1;
|
||||
error = String("unexpected '") + found.substr(1) + String("' found");
|
||||
}
|
||||
|
||||
bool expect(String token_str, String in_mode)
|
||||
{
|
||||
if(error_location) return(false);
|
||||
String found = look_ahead(0);
|
||||
if(found == token_str)
|
||||
{
|
||||
consume();
|
||||
return(true);
|
||||
}
|
||||
error_location = token_index;
|
||||
token_index = tokens.size() + 1;
|
||||
error = String("'") + token_str.substr(1) + "' expected but '" + found.substr(1) + "' found in "+in_mode.substr(1);
|
||||
return(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ASTNode* script_parse_expression(ParserState* state, String accept_delim);
|
||||
ASTNode* script_parse_expression(ParserState* state, String delim1, String delim2);
|
||||
ASTNode* script_parse_declaration(ParserState* state, String delim1, String delim2);
|
||||
|
||||
ASTNode* script_parse_call_params(ParserState* state)
|
||||
ASTNode* script_parse_declaration(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('P');
|
||||
while(state->look_ahead(0) != ")")
|
||||
{
|
||||
state->next();
|
||||
}
|
||||
state->consume(")");
|
||||
return(result);
|
||||
}
|
||||
ASTNode* result = new ASTNode('D');
|
||||
|
||||
ASTNode* script_parse_expression(ParserState* state, String accept_delim)
|
||||
{
|
||||
ASTNode* result = new ASTNode('E');
|
||||
String tname = state->next();
|
||||
String tnx = state->look_ahead(0);
|
||||
if(tnx == ":")
|
||||
String ident = state->consume();
|
||||
if(ident[0] != 'I')
|
||||
{
|
||||
// declaration
|
||||
result->type = 'D';
|
||||
result->identifier = tname;
|
||||
state->consume(":");
|
||||
if(state->look_ahead(0) != "=")
|
||||
result->type_name = state->next();
|
||||
if(state->look_ahead(0) == "=")
|
||||
{
|
||||
state->consume("=");
|
||||
result->assign = script_parse_expression(state, accept_delim);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->consume(accept_delim);
|
||||
}
|
||||
state->unexpected_token(-1);
|
||||
return(result);
|
||||
}
|
||||
else if(tnx == "=")
|
||||
result->identifier = ident.substr(1);
|
||||
|
||||
if(!state->expect("O:", "declaration"))
|
||||
return(result);
|
||||
|
||||
String n0 = state->look_ahead(0);
|
||||
if(n0 == "O=")
|
||||
{
|
||||
// assignment
|
||||
result->type = 'A';
|
||||
result->identifier = tname;
|
||||
state->consume("=");
|
||||
result->assign = script_parse_expression(state, accept_delim);
|
||||
result->type_name = "auto";
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// who knows
|
||||
result->type = 'E';
|
||||
result->identifier = tname;
|
||||
tnx = state->look_ahead(0);
|
||||
if(tnx == "(")
|
||||
result->type_name = state->consume('I').substr(1);
|
||||
String n2 = state->look_ahead(0);
|
||||
if(n2 == delim1 || n2 == delim2)
|
||||
{
|
||||
result->type = 'C';
|
||||
result->call_params = script_parse_call_params(state);
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
state->consume(accept_delim);
|
||||
else if(n2 == "O=")
|
||||
{
|
||||
state->expect("O=", "declaration");
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token();
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* parse_single_token(ParserState* state)
|
||||
{
|
||||
ASTNode* result = new ASTNode('?');
|
||||
|
||||
String n = state->consume();
|
||||
if(n[0] == 'Q')
|
||||
{
|
||||
result->type = 'S';
|
||||
result->string_literal = n.substr(1);
|
||||
}
|
||||
else if(n[0] == 'N')
|
||||
{
|
||||
result->type = 'N';
|
||||
result->string_literal = n.substr(1);
|
||||
}
|
||||
else if(n[0] == 'I')
|
||||
{
|
||||
result->type = 'I';
|
||||
result->identifier = n.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token(-1);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* script_parse_assignment(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('A');
|
||||
result->identifier = state->consume('I').substr(1);
|
||||
state->expect("O=", "assignment");
|
||||
result->assign.push_back(script_parse_expression(state, delim1, delim2));
|
||||
return(result);
|
||||
}
|
||||
|
||||
ASTNode* script_parse_expression(ParserState* state, String delim1, String delim2)
|
||||
{
|
||||
ASTNode* result = new ASTNode('E');
|
||||
|
||||
String n = state->look_ahead(0);
|
||||
|
||||
if(n == "O(")
|
||||
{
|
||||
state->consume();
|
||||
result->children.push_back(script_parse_expression(state, "O)", ""));
|
||||
}
|
||||
else if(n == delim1 || n == delim2)
|
||||
{
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
String n2 = state->look_ahead(1);
|
||||
if(n[0] == 'I' && n2 == "O:")
|
||||
{
|
||||
return(script_parse_declaration(state, "O;", ""));
|
||||
}
|
||||
else if(n2 == delim1 || n2 == delim2)
|
||||
{
|
||||
// single component 'expression'
|
||||
result = parse_single_token(state);
|
||||
state->consume();
|
||||
return(result);
|
||||
}
|
||||
else if(n[0] == 'I' && n2 == "O=")
|
||||
{
|
||||
result = script_parse_assignment(state, delim1, delim2);
|
||||
n2 = state->look_ahead(0);
|
||||
if(n2 != delim1 && n2 != delim2)
|
||||
{
|
||||
state->unexpected_token();
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->unexpected_token();
|
||||
state->error += " in expression";
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
@ -206,21 +318,13 @@ ParserState* script_parse(StringList tokens)
|
||||
{
|
||||
ParserState* state = new ParserState();
|
||||
state->tokens = tokens;
|
||||
state->root = new ASTNode('R');
|
||||
ASTNode* current_node = 0;
|
||||
state->root = new ASTNode('M');
|
||||
|
||||
while(state->token_index < state->tokens.size())
|
||||
{
|
||||
if(!current_node)
|
||||
{
|
||||
current_node = script_parse_expression(state, ";");
|
||||
state->root->children = current_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_node->next = script_parse_expression(state, ";");
|
||||
current_node = current_node->next;
|
||||
}
|
||||
state->root->children.push_back(script_parse_expression(state, "O;", ""));
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
@ -235,20 +339,25 @@ RENDER()
|
||||
</h1>
|
||||
</>
|
||||
|
||||
String script_src = first(context->post["code"], file_get_contents("script-example1.usp"));
|
||||
|
||||
<>
|
||||
<h3>Code</h3>
|
||||
<form action="?" method="post">
|
||||
<textarea name="code"><?= first(context->post["code"]) ?></textarea>
|
||||
<textarea name="code"><?= script_src ?></textarea>
|
||||
<input type="submit" value="parse"/>
|
||||
</form>
|
||||
<pre><?
|
||||
|
||||
StringList tokens = script_tokenize(context->post["code"]);
|
||||
StringList tokens = script_tokenize(script_src);
|
||||
//print(var_dump(tokens));
|
||||
|
||||
ParserState* ps = script_parse(tokens);
|
||||
|
||||
print(ps->error+"\n");
|
||||
if(ps->error_location > 0)
|
||||
{
|
||||
print(ps->error, " @ token ", 1+ps->error_location, "\n");
|
||||
}
|
||||
|
||||
print(ps->root->to_string());
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user