Compare commits
33 Commits
34114ca451
...
d333497a03
| Author | SHA1 | Date | |
|---|---|---|---|
| d333497a03 | |||
| 28f8c8f71c | |||
| bb09e8b8d1 | |||
| 446ee99306 | |||
| 070a2be969 | |||
| 862028f5a8 | |||
| d7443d7810 | |||
| f772f4ba20 | |||
| 0ee1a3575d | |||
| 92e58ec7c6 | |||
| 8f7a0b9fb8 | |||
| b6aeb8d4bf | |||
| d8c694a43e | |||
| 4f65e3b9f2 | |||
| c9cf6b229e | |||
| c3bf6dcee6 | |||
| e679c41725 | |||
| 30bfce5701 | |||
| e829c77297 | |||
| ca8533334b | |||
| fad13b5476 | |||
| 82a035f5cc | |||
| 5a23da4cfe | |||
| 2f200e8d1b | |||
| f629b05672 | |||
| 58b4bb2c51 | |||
| 0e8dc9cb6f | |||
| 2cee984092 | |||
| 1f8b9ff0d3 | |||
| e490754625 | |||
| 405686f6ec | |||
| d78f80a121 | |||
| 05dcf1f8b6 |
@@ -0,0 +1,60 @@
|
|||||||
|
BasedOnStyle: WebKit
|
||||||
|
IndentWidth: 8
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
PointerAlignment: Right
|
||||||
|
ColumnLimit: 80
|
||||||
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
AlignConsecutiveAssignments: None
|
||||||
|
AlignConsecutiveBitFields: None
|
||||||
|
AlignConsecutiveDeclarations: None
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: AlignAfterOperator
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: false
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLambdasOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
SortIncludes: true
|
||||||
|
IndentRequires: true
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
ReflowComments: true
|
||||||
|
SpacesBeforeTrailingComments: 3
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: AlignWithSpaces
|
||||||
|
BreakAfterReturnType: Automatic
|
||||||
|
PenaltyBreakAssignment: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 100000000
|
||||||
|
PenaltyExcessCharacter: 10000000
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 0
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
AttributeMacros:
|
||||||
|
- FX_API
|
||||||
|
ForEachMacros:
|
||||||
|
- fx_btree_foreach
|
||||||
|
- fx_queue_foreach
|
||||||
|
MacroBlockBegin: "FX_(TYPE|ASSEMBLY).*_BEGIN"
|
||||||
|
MacroBlockEnd: "FX_(TYPE|ASSEMBLY).*_END"
|
||||||
+25
-2
@@ -3,6 +3,10 @@ project(bshell C)
|
|||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
if (NOT DEFINED bshell_interactive)
|
||||||
|
set(bshell_interactive 1)
|
||||||
|
endif ()
|
||||||
|
|
||||||
find_package(Python COMPONENTS Interpreter REQUIRED)
|
find_package(Python COMPONENTS Interpreter REQUIRED)
|
||||||
find_package(FX REQUIRED COMPONENTS
|
find_package(FX REQUIRED COMPONENTS
|
||||||
fx.runtime
|
fx.runtime
|
||||||
@@ -14,14 +18,33 @@ execute_process(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/tools/build-id.py
|
${CMAKE_CURRENT_SOURCE_DIR}/tools/build-id.py
|
||||||
OUTPUT_VARIABLE bshell_version)
|
OUTPUT_VARIABLE bshell_version)
|
||||||
|
|
||||||
file(GLOB_RECURSE bshell_sources
|
set(source_dirs
|
||||||
|
ast compile parse parse/lex parse/syntax
|
||||||
|
runtime format command cmdlets aliases)
|
||||||
|
|
||||||
|
if (bshell_interactive EQUAL 1)
|
||||||
|
message(STATUS "Interactive support: Enabled")
|
||||||
|
set(source_dirs ${source_dirs} line-ed)
|
||||||
|
else ()
|
||||||
|
message(STATUS "Interactive support: Disabled")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
file(GLOB bshell_sources
|
||||||
bshell/*.c
|
bshell/*.c
|
||||||
bshell/*.h)
|
bshell/*.h)
|
||||||
|
|
||||||
|
foreach (d ${source_dirs})
|
||||||
|
file(GLOB sources
|
||||||
|
bshell/${d}/*.c
|
||||||
|
bshell/${d}/*.h)
|
||||||
|
set(bshell_sources ${bshell_sources} ${sources})
|
||||||
|
endforeach (d)
|
||||||
|
|
||||||
message(STATUS "B Shell version: ${bshell_version}")
|
message(STATUS "B Shell version: ${bshell_version}")
|
||||||
|
|
||||||
add_executable(bshell ${bshell_sources})
|
add_executable(bshell ${bshell_sources})
|
||||||
|
|
||||||
target_link_libraries(bshell FX::Runtime FX::Collections FX::Term)
|
target_link_libraries(bshell FX::Runtime FX::Collections FX::Term)
|
||||||
target_compile_definitions(bshell PUBLIC
|
target_compile_definitions(bshell PUBLIC
|
||||||
BSHELL_VERSION="${bshell_version}")
|
BSHELL_VERSION="${bshell_version}"
|
||||||
|
BSHELL_INTERACTIVE=${bshell_interactive})
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ set cpoptions&vim
|
|||||||
setlocal iskeyword+=-
|
setlocal iskeyword+=-
|
||||||
|
|
||||||
syn match bshellFunctionRef /\<[A-Za-z][A-Za-z0-9]*\(-[A-Za-z0-9][A-Za-z0-9]*\)\+\>/
|
syn match bshellFunctionRef /\<[A-Za-z][A-Za-z0-9]*\(-[A-Za-z0-9][A-Za-z0-9]*\)\+\>/
|
||||||
syn match bshellVariable /\$[A-Za-z][A-Za-z0-9_]*/
|
syn match bshellVariable /\$[A-Za-z_][A-Za-z0-9_]*/
|
||||||
syn match bshellArgFlag /\<-[A-Za-z][A-Za-z0-9]*\(-[A-Za-z0-9][A-Za-z0-9]*\)*\>/
|
syn match bshellArgFlag /\<-[A-Za-z][A-Za-z0-9]*\(-[A-Za-z0-9][A-Za-z0-9]*\)*\>/
|
||||||
syn keyword bshellKeyword func
|
syn keyword bshellKeyword func if elseif else
|
||||||
|
|
||||||
|
syn keyword bshellBuiltinCommand echo
|
||||||
|
|
||||||
syn keyword bshellTodo contained TODO FIXME XXX NOTE HACK TBD
|
syn keyword bshellTodo contained TODO FIXME XXX NOTE HACK TBD
|
||||||
syn match bshellLineComment /#.*$/ contains=bshellTodo
|
syn match bshellLineComment /#.*$/ contains=bshellTodo
|
||||||
@@ -33,16 +35,33 @@ syn case match
|
|||||||
syn cluster bshellNumber contains=bshellInteger,bshellReal
|
syn cluster bshellNumber contains=bshellInteger,bshellReal
|
||||||
|
|
||||||
syn cluster bshellLiteral contains=@bshellNumber,@bshellString
|
syn cluster bshellLiteral contains=@bshellNumber,@bshellString
|
||||||
syn cluster bshellAll contains=@bshellLiteral,bshellVariable,bshellKeyword,bshellArgFlag,bshellFunctionRef,bshellSymbolOp,bshellKeywordOp
|
syn cluster bshellAll contains=
|
||||||
|
\ @bshellLiteral,bshellVariable,bshellKeyword,bshellArgFlag,
|
||||||
|
\ bshellFunctionRef,bshellBuiltinCommand,bshellSymbolOp,
|
||||||
|
\ bshellKeywordOp,bshellTerminator,bshellControlSymbols,
|
||||||
|
\ bshellBraces,bshellParens,bshellStructureDelimiter
|
||||||
|
|
||||||
syn match bshellSymbolOp "[+]" display
|
syn match bshellBraces "[{}]" display
|
||||||
syn keyword bshellKeywordOp is not understands and or
|
syn match bshellParens "[()]" display
|
||||||
|
syn match bshellStructureDelimiter "@[{(]" display
|
||||||
|
syn match bshellControlSymbols "[[\]]" display
|
||||||
|
syn match bshellControlSymbols "|" display
|
||||||
|
syn match bshellSymbolOp "\*" display
|
||||||
|
syn match bshellSymbolOp "[\/*%&!,]" display
|
||||||
|
syn match bshellSymbolOp "[+\-/*%!]=" display
|
||||||
|
syn match bshellSymbolOp "\s\+[\-+]\s\+" display
|
||||||
|
syn match bshellTerminator "[;]" display
|
||||||
|
syn keyword bshellKeywordOp -f -band -bor -bxor -bnot -shl -shr
|
||||||
|
\ -eq -ne -gt -lt -ge -le -match -notmatch -replace
|
||||||
|
\ -like -notlike -in -notin -contains -notcontains
|
||||||
|
\ -and -or -xor -not -split -join -is -isnot -as
|
||||||
|
|
||||||
hi def link bshellKeyword Statement
|
hi def link bshellKeyword Statement
|
||||||
hi def link bshellArgFlag Tag
|
hi def link bshellArgFlag Tag
|
||||||
hi def link bshellVariable Identifier
|
hi def link bshellVariable Identifier
|
||||||
hi def link bshellLineComment Comment
|
hi def link bshellLineComment Comment
|
||||||
hi def link bshellFunctionRef Function
|
hi def link bshellFunctionRef Function
|
||||||
|
hi def link bshellBuiltinCommand Function
|
||||||
hi def link bshellString String
|
hi def link bshellString String
|
||||||
hi def link bshellInterpolatedString String
|
hi def link bshellInterpolatedString String
|
||||||
hi def link bshellLiteralString String
|
hi def link bshellLiteralString String
|
||||||
@@ -50,8 +69,13 @@ hi def link bshellInteger Number
|
|||||||
hi def link bshellReal Float
|
hi def link bshellReal Float
|
||||||
|
|
||||||
hi def link bshellInterpolationDelimiter Delimiter
|
hi def link bshellInterpolationDelimiter Delimiter
|
||||||
|
hi def link bshellStructureDelimiter Delimiter
|
||||||
|
hi def link bshellBraces Delimiter
|
||||||
|
hi def link bshellParens Delimiter
|
||||||
|
hi def link bshellControlSymbols Operator
|
||||||
hi def link bshellSymbolOp Operator
|
hi def link bshellSymbolOp Operator
|
||||||
hi def link bshellKeywordOp Operator
|
hi def link bshellKeywordOp Operator
|
||||||
|
hi def link bshellTerminator Delimiter
|
||||||
|
|
||||||
" The default highlighting.
|
" The default highlighting.
|
||||||
" hi def link bshellUnspecifiedStatement Statement
|
" hi def link bshellUnspecifiedStatement Statement
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include "../command/alias.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_ECHO (bshell_echo_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_echo_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_echo);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_echo)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_echo)
|
||||||
|
|
||||||
|
struct bshell_echo_p {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_echo)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_alias, BSHELL_TYPE_ALIAS)
|
||||||
|
FX_INTERFACE_ENTRY(a_callable_name) = "echo";
|
||||||
|
FX_INTERFACE_ENTRY(a_target_name) = "Write-Output";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_echo)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_echo)
|
||||||
|
FX_TYPE_ID(0xedd507bf, 0x2e32, 0x425b, 0x9c73, 0x2ba9539eace0);
|
||||||
|
FX_TYPE_NAME("bshell.core.echo");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_ALIAS);
|
||||||
|
FX_TYPE_CLASS(bshell_echo_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_echo_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_echo)
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include "../command/alias.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_PERCENT (bshell_percent_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_percent_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_percent);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_percent)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_percent)
|
||||||
|
|
||||||
|
struct bshell_percent_p {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_percent)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_alias, BSHELL_TYPE_ALIAS)
|
||||||
|
FX_INTERFACE_ENTRY(a_callable_name) = "%";
|
||||||
|
FX_INTERFACE_ENTRY(a_target_name) = "ForEach-Object";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_percent)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_percent)
|
||||||
|
FX_TYPE_ID(0x4255a9de, 0xd6f6, 0x4708, 0x829c, 0xffa4c6034edb);
|
||||||
|
FX_TYPE_NAME("bshell.core.percent");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_ALIAS);
|
||||||
|
FX_TYPE_CLASS(bshell_percent_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_percent_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_percent)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/reflection/assembly.h>
|
||||||
|
|
||||||
|
FX_ASSEMBLY_BEGIN(bshell)
|
||||||
|
FX_ASSEMBLY_NAME("bshell");
|
||||||
|
FX_ASSEMBLY_VERSION(0, 1, 0, 0);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE("bshell", "cmdlet", bshell_cmdlet);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE("bshell", "scriptblock", bshell_scriptblock);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "get_verb", bshell_get_verb);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE(
|
||||||
|
"bshell.core",
|
||||||
|
"write_output",
|
||||||
|
bshell_write_output);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE(
|
||||||
|
"bshell.core",
|
||||||
|
"foreach_object",
|
||||||
|
bshell_foreach_object);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE(
|
||||||
|
"bshell.core",
|
||||||
|
"get_command",
|
||||||
|
bshell_get_command);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "percent", bshell_percent);
|
||||||
|
FX_ASSEMBLY_EXPORT_TYPE("bshell.core", "echo", bshell_echo);
|
||||||
|
FX_ASSEMBLY_END(bshell)
|
||||||
+91
-17
@@ -26,7 +26,7 @@ extern struct ast_node_definition if_ast_node;
|
|||||||
extern struct ast_node_definition if_branch_ast_node;
|
extern struct ast_node_definition if_branch_ast_node;
|
||||||
extern struct ast_node_definition op_ast_node;
|
extern struct ast_node_definition op_ast_node;
|
||||||
|
|
||||||
static const struct ast_node_definition *ast_node_defintions[] = {
|
static const struct ast_node_definition *ast_node_definitions[] = {
|
||||||
[AST_NULL] = &null_ast_node,
|
[AST_NULL] = &null_ast_node,
|
||||||
[AST_INT] = &int_ast_node,
|
[AST_INT] = &int_ast_node,
|
||||||
[AST_DOUBLE] = &double_ast_node,
|
[AST_DOUBLE] = &double_ast_node,
|
||||||
@@ -47,14 +47,14 @@ static const struct ast_node_definition *ast_node_defintions[] = {
|
|||||||
[AST_HASHTABLE_ITEM] = &hashtable_item_ast_node,
|
[AST_HASHTABLE_ITEM] = &hashtable_item_ast_node,
|
||||||
[AST_OP] = &op_ast_node,
|
[AST_OP] = &op_ast_node,
|
||||||
};
|
};
|
||||||
static const size_t nr_ast_node_definitions
|
static const size_t nr_ast_node_definitions = sizeof ast_node_definitions
|
||||||
= sizeof ast_node_defintions / sizeof ast_node_defintions[0];
|
/ sizeof ast_node_definitions[0];
|
||||||
|
|
||||||
struct ast_node *ast_node_create(enum ast_node_type type)
|
struct ast_node *ast_node_create(enum ast_node_type type)
|
||||||
{
|
{
|
||||||
assert(type < nr_ast_node_definitions);
|
assert(type < nr_ast_node_definitions);
|
||||||
|
|
||||||
const struct ast_node_definition *def = ast_node_defintions[type];
|
const struct ast_node_definition *def = ast_node_definitions[type];
|
||||||
struct ast_node *out = malloc(def->def_node_size);
|
struct ast_node *out = malloc(def->def_node_size);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -80,8 +80,8 @@ void ast_node_destroy(struct ast_node *node)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
|
|
||||||
if (def->def_cleanup) {
|
if (def->def_cleanup) {
|
||||||
def->def_cleanup(node);
|
def->def_cleanup(node);
|
||||||
@@ -92,15 +92,10 @@ void ast_node_destroy(struct ast_node *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_node_iterate(struct ast_node *node, struct ast_iterator *it)
|
|
||||||
{
|
|
||||||
ast_iterator_enqueue(it, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ast_node_to_string(const struct ast_node *node, fx_bstr *out)
|
void ast_node_to_string(const struct ast_node *node, fx_bstr *out)
|
||||||
{
|
{
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
if (def->def_to_string) {
|
if (def->def_to_string) {
|
||||||
def->def_to_string(node, out);
|
def->def_to_string(node, out);
|
||||||
}
|
}
|
||||||
@@ -158,8 +153,8 @@ struct ast_node *ast_iterator_dequeue(struct ast_iterator *it)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry);
|
struct ast_node *node = fx_unbox(struct ast_node, cur, n_it.e_entry);
|
||||||
const struct ast_node_definition *def
|
const struct ast_node_definition *def = ast_node_definitions
|
||||||
= ast_node_defintions[node->n_type];
|
[node->n_type];
|
||||||
|
|
||||||
it->it_insert_after = cur;
|
it->it_insert_after = cur;
|
||||||
if (def->def_collect_children) {
|
if (def->def_collect_children) {
|
||||||
@@ -176,8 +171,10 @@ void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node)
|
|||||||
|
|
||||||
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
fx_queue_entry *cur = fx_queue_first(&it->it_queue);
|
||||||
if (cur) {
|
if (cur) {
|
||||||
struct ast_node *cur_node
|
struct ast_node *cur_node = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, cur, n_it.e_entry);
|
struct ast_node,
|
||||||
|
cur,
|
||||||
|
n_it.e_entry);
|
||||||
new_depth = cur_node->n_it.e_depth + 1;
|
new_depth = cur_node->n_it.e_depth + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,3 +191,80 @@ void ast_iterator_enqueue(struct ast_iterator *it, struct ast_node *node)
|
|||||||
it->it_insert_after);
|
it->it_insert_after);
|
||||||
it->it_insert_after = &node->n_it.e_entry;
|
it->it_insert_after = &node->n_it.e_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum bshell_status ast_node_iterate(
|
||||||
|
struct ast_node *node,
|
||||||
|
struct ast_iterator *it,
|
||||||
|
ast_iterator_callback callback,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
fx_queue_push_back(&it->it_queue, &node->n_it.e_entry);
|
||||||
|
node->n_it.e_depth = 0;
|
||||||
|
|
||||||
|
fx_queue_entry *entry = fx_queue_first(&it->it_queue);
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
struct ast_iterator_entry *it_entry = fx_unbox(
|
||||||
|
struct ast_iterator_entry,
|
||||||
|
entry,
|
||||||
|
e_entry);
|
||||||
|
node = fx_unbox(struct ast_node, it_entry, n_it);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
/* this should never happen. */
|
||||||
|
return BSHELL_ERR_INTERNAL_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ast_iterate_result result = callback(
|
||||||
|
node,
|
||||||
|
AST_ITERATION_PRE,
|
||||||
|
it,
|
||||||
|
arg);
|
||||||
|
if (result.r_status != BSHELL_SUCCESS
|
||||||
|
|| result.r_flags & AST_ITERATE_STOP) {
|
||||||
|
return result.r_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ast_node_definition *type = ast_node_definitions
|
||||||
|
[node->n_type];
|
||||||
|
if (type->def_collect_children
|
||||||
|
&& result.r_flags & AST_ITERATE_ADD_CHILDREN) {
|
||||||
|
it->it_insert_after = entry;
|
||||||
|
type->def_collect_children(node, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(result.r_flags & AST_ITERATE_REPEAT)) {
|
||||||
|
entry = fx_queue_next(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!fx_queue_empty(&it->it_queue)) {
|
||||||
|
fx_queue_entry *entry = fx_queue_last(&it->it_queue);
|
||||||
|
if (!entry) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fx_unbox(struct ast_node, entry, n_it);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
/* this should never happen. */
|
||||||
|
return BSHELL_ERR_INTERNAL_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ast_iterate_result result = callback(
|
||||||
|
node,
|
||||||
|
AST_ITERATION_POST,
|
||||||
|
it,
|
||||||
|
arg);
|
||||||
|
if (result.r_status != BSHELL_SUCCESS
|
||||||
|
|| result.r_flags & AST_ITERATE_STOP) {
|
||||||
|
return result.r_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(result.r_flags & AST_ITERATE_REPEAT)) {
|
||||||
|
fx_queue_pop_back(&it->it_queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|||||||
+32
-1
@@ -8,6 +8,12 @@
|
|||||||
|
|
||||||
struct lex_token;
|
struct lex_token;
|
||||||
|
|
||||||
|
#define AST_ITERATE_OK(flags) \
|
||||||
|
((struct ast_iterate_result) {.r_status = BSHELL_SUCCESS, \
|
||||||
|
.r_flags = (flags)})
|
||||||
|
#define AST_ITERATE_ERR(status) \
|
||||||
|
((struct ast_iterate_result) {.r_status = (status)})
|
||||||
|
|
||||||
enum ast_node_type {
|
enum ast_node_type {
|
||||||
AST_NONE = 0x00u,
|
AST_NONE = 0x00u,
|
||||||
AST_NULL,
|
AST_NULL,
|
||||||
@@ -170,6 +176,27 @@ struct ast_iterator {
|
|||||||
fx_queue_entry *it_insert_after;
|
fx_queue_entry *it_insert_after;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ast_iterate_result {
|
||||||
|
enum bshell_status r_status;
|
||||||
|
enum {
|
||||||
|
AST_ITERATE_CONTINUE = 0x00u,
|
||||||
|
AST_ITERATE_STOP = 0x01u,
|
||||||
|
AST_ITERATE_ADD_CHILDREN = 0x02u,
|
||||||
|
AST_ITERATE_REPEAT = 0x04u,
|
||||||
|
} r_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ast_iteration_type {
|
||||||
|
AST_ITERATION_PRE,
|
||||||
|
AST_ITERATION_POST,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ast_iterate_result (*ast_iterator_callback)(
|
||||||
|
struct ast_node *,
|
||||||
|
enum ast_iteration_type,
|
||||||
|
struct ast_iterator *,
|
||||||
|
void *);
|
||||||
|
|
||||||
struct ast_node_definition {
|
struct ast_node_definition {
|
||||||
enum ast_node_type def_id;
|
enum ast_node_type def_id;
|
||||||
size_t def_node_size;
|
size_t def_node_size;
|
||||||
@@ -182,8 +209,12 @@ struct ast_node_definition {
|
|||||||
|
|
||||||
extern struct ast_node *ast_node_create(enum ast_node_type type);
|
extern struct ast_node *ast_node_create(enum ast_node_type type);
|
||||||
extern void ast_node_destroy(struct ast_node *node);
|
extern void ast_node_destroy(struct ast_node *node);
|
||||||
extern void ast_node_iterate(struct ast_node *node, struct ast_iterator *it);
|
|
||||||
extern void ast_node_to_string(const struct ast_node *node, fx_bstr *out);
|
extern void ast_node_to_string(const struct ast_node *node, fx_bstr *out);
|
||||||
|
extern enum bshell_status ast_node_iterate(
|
||||||
|
struct ast_node *node,
|
||||||
|
struct ast_iterator *it,
|
||||||
|
ast_iterator_callback callback,
|
||||||
|
void *arg);
|
||||||
|
|
||||||
extern const char *ast_node_type_to_string(enum ast_node_type type);
|
extern const char *ast_node_type_to_string(enum ast_node_type type);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
|
#include "../parse/token.h"
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
|
||||||
|
#include <fx/stream.h>
|
||||||
|
|
||||||
|
static void to_string(const struct ast_node *node, fx_bstr *out)
|
||||||
|
{
|
||||||
|
struct double_ast_node *i = (struct double_ast_node *)node;
|
||||||
|
fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
struct ast_node_definition double_ast_node = {
|
struct ast_node_definition double_ast_node = {
|
||||||
.def_id = AST_DOUBLE,
|
.def_id = AST_DOUBLE,
|
||||||
.def_node_size = sizeof(struct double_ast_node),
|
.def_node_size = sizeof(struct double_ast_node),
|
||||||
|
.def_to_string = to_string,
|
||||||
};
|
};
|
||||||
|
|||||||
+3
-1
@@ -1,10 +1,12 @@
|
|||||||
#include "../parse/token.h"
|
#include "../parse/token.h"
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
|
||||||
|
#include <fx/stream.h>
|
||||||
|
|
||||||
static void to_string(const struct ast_node *node, fx_bstr *out)
|
static void to_string(const struct ast_node *node, fx_bstr *out)
|
||||||
{
|
{
|
||||||
struct int_ast_node *i = (struct int_ast_node *)node;
|
struct int_ast_node *i = (struct int_ast_node *)node;
|
||||||
fx_bstr_write_fmt(out, NULL, "%lld", i->n_value->tok_int);
|
fx_value_to_string(&i->n_value->tok_number, (fx_stream *)out, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast_node_definition int_ast_node = {
|
struct ast_node_definition int_ast_node = {
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#include "../command/cmdlet.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../runtime/runtime.h"
|
||||||
|
#include "../script-block.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_FOREACH_OBJECT (bshell_foreach_object_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_foreach_object_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_foreach_object);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_foreach_object)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_foreach_object)
|
||||||
|
|
||||||
|
struct bshell_foreach_object_p {
|
||||||
|
bshell_scriptblock *f_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_foreach_object_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_FOREACH_OBJECT);
|
||||||
|
|
||||||
|
const fx_value *block_v = bshell_command_get_arg(cmdlet, 1);
|
||||||
|
if (!block_v) {
|
||||||
|
return BSHELL_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_get_object(block_v, &p->f_block);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_record(
|
||||||
|
bshell_cmdlet *cmdlet,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
struct bshell_foreach_object_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_FOREACH_OBJECT);
|
||||||
|
|
||||||
|
fx_value in = bshell_pipeline_read_value(pipeline);
|
||||||
|
if (!fx_value_is_set(&in)) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_runtime_push_scope(rt, p->f_block);
|
||||||
|
bshell_variable *item = bshell_runtime_define_var(rt, "_");
|
||||||
|
bshell_variable_set_value(item, &in);
|
||||||
|
fx_value out = bshell_runtime_eval(rt);
|
||||||
|
bshell_runtime_pop_scope(rt);
|
||||||
|
fx_value_unset(&in);
|
||||||
|
bshell_pipeline_write_value(pipeline, out, false);
|
||||||
|
fx_value_unset(&out);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_foreach_object_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_FOREACH_OBJECT);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_foreach_object)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_FOREACH;
|
||||||
|
FX_INTERFACE_ENTRY(c_noun) = "Object";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
||||||
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
||||||
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_foreach_object)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_foreach_object)
|
||||||
|
FX_TYPE_ID(0x44ae3223, 0x14b3, 0x4c89, 0x9753, 0x6c7901ae00e9);
|
||||||
|
FX_TYPE_NAME("bshell.core.foreach_object");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
|
||||||
|
FX_TYPE_CLASS(bshell_foreach_object_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_foreach_object_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_foreach_object)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/object.h>
|
||||||
|
#include <fx/stream.h>
|
||||||
|
|
||||||
|
enum bshell_status do_format_table(fx_object *object, fx_stream *dest)
|
||||||
|
{
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
#include "../command/cmdlet.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../runtime/runtime.h"
|
||||||
|
#include "../runtime/scope.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/assembly.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_GET_COMMAND (bshell_get_command_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_get_command_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_get_command);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_get_command)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_get_command)
|
||||||
|
|
||||||
|
struct bshell_get_command_p {
|
||||||
|
bool c_eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const fx_assembly *bshell_assembly_get(void);
|
||||||
|
|
||||||
|
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_get_command_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_COMMAND);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_record(
|
||||||
|
bshell_cmdlet *cmdlet,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
struct bshell_get_command_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_COMMAND);
|
||||||
|
if (p->c_eof) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_iterator *it = fx_iterator_begin(rt->rt_aliases);
|
||||||
|
fx_foreach(item_v, it)
|
||||||
|
{
|
||||||
|
fx_hashtable_item *item;
|
||||||
|
fx_value_get_object(&item_v, &item);
|
||||||
|
fx_value alias_v = fx_hashtable_item_get_value(item);
|
||||||
|
bshell_pipeline_write_value(pipeline, alias_v, false);
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
|
||||||
|
while (cur) {
|
||||||
|
struct runtime_scope *scope = fx_unbox(
|
||||||
|
struct runtime_scope,
|
||||||
|
cur,
|
||||||
|
s_entry);
|
||||||
|
|
||||||
|
it = fx_iterator_begin(scope->s_functions);
|
||||||
|
fx_foreach(item_v, it)
|
||||||
|
{
|
||||||
|
fx_hashtable_item *item;
|
||||||
|
fx_value_get_object(&item_v, &item);
|
||||||
|
fx_value func_v = fx_hashtable_item_get_value(item);
|
||||||
|
bshell_pipeline_write_value(pipeline, func_v, false);
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
cur = fx_queue_prev(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fx_assembly *self = bshell_assembly_get();
|
||||||
|
it = fx_assembly_get_types(self);
|
||||||
|
fx_foreach(v, it)
|
||||||
|
{
|
||||||
|
fx_type *ty = NULL;
|
||||||
|
fx_value_get_object(&v, &ty);
|
||||||
|
if (fx_type_id_compare(fx_type_get_id(ty), BSHELL_TYPE_CMDLET)
|
||||||
|
== 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bshell_command_class *cmd = fx_type_get_interface(
|
||||||
|
ty,
|
||||||
|
BSHELL_TYPE_COMMAND);
|
||||||
|
if (!cmd) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value callable = FX_VALUE_OBJECT(
|
||||||
|
fx_object_create(fx_type_get_id(ty)));
|
||||||
|
bshell_pipeline_write_value(pipeline, callable, false);
|
||||||
|
fx_value_unset(&callable);
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
p->c_eof = true;
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_get_command_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_COMMAND);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_get_command)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_GET;
|
||||||
|
FX_INTERFACE_ENTRY(c_noun) = "Command";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
||||||
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
||||||
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_TYPE_CLASS_END(bshell_get_command)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_get_command)
|
||||||
|
FX_TYPE_ID(0x4f862cc3, 0xf3d3, 0x4f04, 0xb68e, 0x8764079f03c4);
|
||||||
|
FX_TYPE_NAME("bshell.core.get_command");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
|
||||||
|
FX_TYPE_CLASS(bshell_get_command_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_get_command_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_get_command)
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include "../command/cmdlet.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_GET_VERB (bshell_get_verb_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_get_verb_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_get_verb);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_get_verb)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_get_verb)
|
||||||
|
|
||||||
|
struct bshell_get_verb_p {
|
||||||
|
fx_hashtable *c_verbs;
|
||||||
|
fx_iterator *c_it;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_get_verb_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_VERB);
|
||||||
|
p->c_verbs = bshell_get_all_verbs();
|
||||||
|
p->c_it = fx_iterator_begin(p->c_verbs);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_record(
|
||||||
|
bshell_cmdlet *cmdlet,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
struct bshell_get_verb_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_VERB);
|
||||||
|
|
||||||
|
do {
|
||||||
|
fx_value v = fx_iterator_get_value(p->c_it);
|
||||||
|
if (!v.v_type) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_hashtable_item *item = NULL;
|
||||||
|
fx_value_get_object(&v, &item);
|
||||||
|
|
||||||
|
v = fx_hashtable_item_get_value(item);
|
||||||
|
|
||||||
|
bshell_verb *verb = NULL;
|
||||||
|
fx_value_get_object(&v, &verb);
|
||||||
|
fx_iterator_move_next(p->c_it);
|
||||||
|
|
||||||
|
if (bshell_verb_is_reserved(verb)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_verb_ref(verb);
|
||||||
|
bshell_pipeline_write_value(
|
||||||
|
pipeline,
|
||||||
|
fx_value_copy_return(fx_hashtable_item_get_value(item)),
|
||||||
|
false);
|
||||||
|
break;
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_get_verb_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_GET_VERB);
|
||||||
|
if (p->c_it) {
|
||||||
|
fx_iterator_unref(p->c_it);
|
||||||
|
p->c_it = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_get_verb)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_GET;
|
||||||
|
FX_INTERFACE_ENTRY(c_noun) = "Verb";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
||||||
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
||||||
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_TYPE_CLASS_END(bshell_get_verb)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_get_verb)
|
||||||
|
FX_TYPE_ID(0xa47976a6, 0xf7d8, 0x447f, 0x887b, 0x6c5d78b7bd2e);
|
||||||
|
FX_TYPE_NAME("bshell.core.get_verb");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
|
||||||
|
FX_TYPE_CLASS(bshell_get_verb_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_get_verb_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_get_verb)
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
#include "../command/cmdlet.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../format/format.h"
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/value-type.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_WRITE_OUTPUT (bshell_write_output_get_type())
|
||||||
|
|
||||||
|
fx_type_id bshell_write_output_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_write_output);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_write_output)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_write_output)
|
||||||
|
|
||||||
|
struct bshell_write_output_p {
|
||||||
|
struct table_format_ctx w_table_ctx;
|
||||||
|
bool w_table_initialised;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void initialise_table(
|
||||||
|
struct bshell_write_output_p *cmd,
|
||||||
|
const fx_value *first_record)
|
||||||
|
{
|
||||||
|
table_format_ctx_init(&cmd->w_table_ctx, fx_stdout);
|
||||||
|
const fx_type *ty = fx_type_get_by_id(first_record->v_type);
|
||||||
|
table_format_ctx_prepare_columns_from_format(
|
||||||
|
&cmd->w_table_ctx,
|
||||||
|
ty,
|
||||||
|
NULL);
|
||||||
|
table_format_ctx_print_headers(&cmd->w_table_ctx);
|
||||||
|
cmd->w_table_initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool value_requires_table(const fx_value *value)
|
||||||
|
{
|
||||||
|
if (fx_type_is_value_type(value->v_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fx_value_is_type(value, FX_TYPE_STRING)
|
||||||
|
|| fx_value_is_type(value, FX_TYPE_ARRAY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_value(
|
||||||
|
struct bshell_write_output_p *cmd,
|
||||||
|
const fx_value *value)
|
||||||
|
{
|
||||||
|
if (!value_requires_table(value)) {
|
||||||
|
fx_value_to_string(value, fx_stdout, NULL);
|
||||||
|
fx_stream_write_char(fx_stdout, '\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmd->w_table_initialised) {
|
||||||
|
initialise_table(cmd, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
table_format_ctx_print_record(&cmd->w_table_ctx, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status begin_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_write_output_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_WRITE_OUTPUT);
|
||||||
|
for (size_t i = 1;; i++) {
|
||||||
|
const fx_value *v = bshell_command_get_arg(cmdlet, i);
|
||||||
|
if (!v) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_value(p, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_record(
|
||||||
|
bshell_cmdlet *cmdlet,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
struct bshell_write_output_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_WRITE_OUTPUT);
|
||||||
|
|
||||||
|
fx_value in = bshell_pipeline_read_value(pipeline);
|
||||||
|
if (fx_value_is_set(&in)) {
|
||||||
|
write_value(p, &in);
|
||||||
|
fx_value_unset(&in);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status end_processing(bshell_cmdlet *cmdlet)
|
||||||
|
{
|
||||||
|
struct bshell_write_output_p *p = fx_object_get_private(
|
||||||
|
cmdlet,
|
||||||
|
BSHELL_TYPE_WRITE_OUTPUT);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_write_output)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_INTERFACE_ENTRY(c_verb) = BSHELL_VERB_WRITE;
|
||||||
|
FX_INTERFACE_ENTRY(c_noun) = "Output";
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
||||||
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
||||||
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_cmdlet, BSHELL_TYPE_CMDLET)
|
||||||
|
FX_TYPE_CLASS_END(bshell_write_output)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_write_output)
|
||||||
|
FX_TYPE_ID(0xf7f9c42d, 0xc053, 0x4ffc, 0xa8ec, 0x78fef4844ac0);
|
||||||
|
FX_TYPE_NAME("bshell.core.write_output");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_CMDLET);
|
||||||
|
FX_TYPE_CLASS(bshell_write_output_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_write_output_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_write_output)
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
#include "alias.h"
|
||||||
|
|
||||||
|
#include "../status.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_alias_p {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_alias_get_callable_name(
|
||||||
|
const bshell_alias *alias,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
bshell_alias_class *c = fx_object_get_interface(
|
||||||
|
alias,
|
||||||
|
BSHELL_TYPE_ALIAS);
|
||||||
|
if (!c) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *callable_name = c->a_callable_name;
|
||||||
|
if (c->a_get_callable_name) {
|
||||||
|
callable_name = c->a_get_callable_name(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callable_name) {
|
||||||
|
fx_string_append_cstr(out, callable_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_alias_get_target_name(
|
||||||
|
const bshell_alias *alias,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
bshell_alias_class *c = fx_object_get_interface(
|
||||||
|
alias,
|
||||||
|
BSHELL_TYPE_ALIAS);
|
||||||
|
if (!c) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *target_name = c->a_target_name;
|
||||||
|
if (c->a_get_target_name) {
|
||||||
|
target_name = c->a_get_target_name(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_name) {
|
||||||
|
fx_string_append_cstr(out, target_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status get_callable_name_static(
|
||||||
|
const fx_type *ty,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
bshell_alias_class *c = fx_type_get_interface(ty, BSHELL_TYPE_ALIAS);
|
||||||
|
if (!c) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->a_callable_name) {
|
||||||
|
fx_string_append_cstr(out, c->a_callable_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status get_description(
|
||||||
|
const bshell_command *cmd,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
bshell_alias_class *c = fx_object_get_interface(cmd, BSHELL_TYPE_ALIAS);
|
||||||
|
if (!c) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *callable_name = c->a_callable_name;
|
||||||
|
if (c->a_get_callable_name) {
|
||||||
|
callable_name = c->a_get_callable_name(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *target_name = c->a_target_name;
|
||||||
|
if (c->a_get_target_name) {
|
||||||
|
target_name = c->a_get_target_name(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_string_append_cstr(out, callable_name);
|
||||||
|
fx_string_append_cstr(out, " -> ");
|
||||||
|
fx_string_append_cstr(out, target_name);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status get_description_static(const fx_type *ty, fx_string *out)
|
||||||
|
{
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_alias)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_command_type) = "Alias";
|
||||||
|
FX_INTERFACE_ENTRY(c_get_callable_name)
|
||||||
|
= bshell_alias_get_callable_name;
|
||||||
|
FX_INTERFACE_ENTRY(c_get_callable_name_static)
|
||||||
|
= get_callable_name_static;
|
||||||
|
FX_INTERFACE_ENTRY(c_get_description) = get_description;
|
||||||
|
FX_INTERFACE_ENTRY(c_get_description_static)
|
||||||
|
= get_description_static;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_alias)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_alias)
|
||||||
|
FX_TYPE_ID(0x1736c10e, 0xebe6, 0x4ba5, 0x83d9, 0x5da3b7dc706c);
|
||||||
|
FX_TYPE_NAME("bshell.alias");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND);
|
||||||
|
FX_TYPE_CLASS(bshell_alias_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_alias_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_alias)
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef COMMAND_ALIAS_H_
|
||||||
|
#define COMMAND_ALIAS_H_
|
||||||
|
|
||||||
|
#include "../verb.h"
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_ALIAS (bshell_alias_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_alias);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_alias)
|
||||||
|
const char *a_callable_name;
|
||||||
|
const char *a_target_name;
|
||||||
|
const char *(*a_get_callable_name)(const bshell_alias *);
|
||||||
|
const char *(*a_get_target_name)(const bshell_alias *);
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_alias)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_alias_get_type(void);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_alias_get_callable_name(
|
||||||
|
const bshell_alias *alias,
|
||||||
|
fx_string *out);
|
||||||
|
extern enum bshell_status bshell_alias_get_target_name(
|
||||||
|
const bshell_alias *alias,
|
||||||
|
fx_string *out);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#include "cmdlet.h"
|
||||||
|
|
||||||
|
#include "../status.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_cmdlet_p {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status get_callable_name_static(
|
||||||
|
const fx_type *ty,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
bshell_cmdlet_class *class = fx_type_get_interface(
|
||||||
|
ty,
|
||||||
|
BSHELL_TYPE_CMDLET);
|
||||||
|
if (!class) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bshell_verb *verb_info = bshell_verb_get_by_id(class->c_verb);
|
||||||
|
if (!verb_info) {
|
||||||
|
return BSHELL_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_string_append_cstrf(
|
||||||
|
out,
|
||||||
|
"%s-%s",
|
||||||
|
bshell_verb_get_name(verb_info),
|
||||||
|
class->c_noun);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_cmdlet)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_command_type) = "Cmdlet";
|
||||||
|
FX_INTERFACE_ENTRY(c_get_callable_name_static)
|
||||||
|
= get_callable_name_static;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_cmdlet)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_cmdlet)
|
||||||
|
FX_TYPE_ID(0xc71f4d59, 0x8066, 0x4294, 0xa6b0, 0xe1f3eb04f454);
|
||||||
|
FX_TYPE_NAME("bshell.cmdlet");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND);
|
||||||
|
FX_TYPE_CLASS(bshell_cmdlet_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_cmdlet_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_cmdlet)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef COMMAND_CMDLET_H_
|
||||||
|
#define COMMAND_CMDLET_H_
|
||||||
|
|
||||||
|
#include "../verb.h"
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_CMDLET (bshell_cmdlet_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_cmdlet);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_cmdlet)
|
||||||
|
enum bshell_verb_id c_verb;
|
||||||
|
const char *c_noun;
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_cmdlet)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_cmdlet_get_type(void);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/assembly.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/reflection/type.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_command_p {
|
||||||
|
fx_value *cmd_args;
|
||||||
|
size_t cmd_nr_args;
|
||||||
|
bool cmd_args_reversed;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_set_args(
|
||||||
|
struct bshell_command_p *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args)
|
||||||
|
{
|
||||||
|
cmd->cmd_args = args;
|
||||||
|
cmd->cmd_nr_args = nr_args;
|
||||||
|
cmd->cmd_args_reversed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void command_set_args_reverse(
|
||||||
|
struct bshell_command_p *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args)
|
||||||
|
{
|
||||||
|
cmd->cmd_args = args;
|
||||||
|
cmd->cmd_nr_args = nr_args;
|
||||||
|
cmd->cmd_args_reversed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *command_get_arg(
|
||||||
|
struct bshell_command_p *cmd,
|
||||||
|
size_t index)
|
||||||
|
{
|
||||||
|
if (index >= cmd->cmd_nr_args) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd->cmd_args_reversed) {
|
||||||
|
return &cmd->cmd_args[cmd->cmd_nr_args - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cmd->cmd_args[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_command_type(
|
||||||
|
const fx_value *cmd_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_command *cmd = NULL;
|
||||||
|
fx_value_get_object(cmd_v, &cmd);
|
||||||
|
bshell_command_class *cmd_class = fx_object_get_interface(
|
||||||
|
cmd,
|
||||||
|
BSHELL_TYPE_COMMAND);
|
||||||
|
|
||||||
|
*out = FX_CSTR(cmd_class->c_command_type);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_name(
|
||||||
|
const fx_value *cmd_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_command *cmd = NULL;
|
||||||
|
fx_value_get_object(cmd_v, &cmd);
|
||||||
|
bshell_command_class *cmd_class = fx_object_get_interface(
|
||||||
|
cmd,
|
||||||
|
BSHELL_TYPE_COMMAND);
|
||||||
|
|
||||||
|
fx_string *result = fx_string_create();
|
||||||
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
||||||
|
|
||||||
|
if (cmd_class->c_get_description) {
|
||||||
|
cmd_class->c_get_description(cmd, result);
|
||||||
|
} else if (cmd_class->c_get_description_static) {
|
||||||
|
cmd_class->c_get_description_static(ty, result);
|
||||||
|
} else if (cmd_class->c_get_callable_name) {
|
||||||
|
cmd_class->c_get_callable_name(cmd, result);
|
||||||
|
} else if (cmd_class->c_get_callable_name_static) {
|
||||||
|
cmd_class->c_get_callable_name_static(ty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = FX_VALUE_OBJECT(result);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_version(
|
||||||
|
const fx_value *cmd_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_command *cmd = NULL;
|
||||||
|
fx_value_get_object(cmd_v, &cmd);
|
||||||
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
||||||
|
const fx_assembly *assembly = fx_type_get_assembly(ty);
|
||||||
|
|
||||||
|
long major = 0, minor = 0, build = 0, revision = 0;
|
||||||
|
fx_assembly_get_version(assembly, &major, &minor, &build, &revision);
|
||||||
|
|
||||||
|
fx_string *result = fx_string_create();
|
||||||
|
if (revision != 0) {
|
||||||
|
fx_string_append_cstrf(
|
||||||
|
result,
|
||||||
|
"%ld.%ld.%ld.%ld",
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
build,
|
||||||
|
revision);
|
||||||
|
} else {
|
||||||
|
fx_string_append_cstrf(
|
||||||
|
result,
|
||||||
|
"%ld.%ld.%ld",
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
build);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = FX_VALUE_OBJECT(result);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_source(
|
||||||
|
const fx_value *cmd_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_command *cmd = NULL;
|
||||||
|
fx_value_get_object(cmd_v, &cmd);
|
||||||
|
const fx_type *ty = fx_type_get_by_id(fx_object_query_type(cmd));
|
||||||
|
const fx_assembly *assembly = fx_type_get_assembly(ty);
|
||||||
|
|
||||||
|
*out = FX_CSTR(fx_assembly_get_name(assembly));
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const fx_assembly *bshell_assembly_get(void);
|
||||||
|
|
||||||
|
bshell_command *bshell_command_find_static(const char *name)
|
||||||
|
{
|
||||||
|
fx_string *target_name = fx_string_create();
|
||||||
|
fx_string *call_name = fx_string_create_from_cstr(name);
|
||||||
|
fx_string_transform_lowercase(call_name);
|
||||||
|
|
||||||
|
const fx_assembly *self = bshell_assembly_get();
|
||||||
|
fx_iterator *it = fx_assembly_get_types(self);
|
||||||
|
fx_foreach(v, it)
|
||||||
|
{
|
||||||
|
fx_type *ty = NULL;
|
||||||
|
fx_value_get_object(&v, &ty);
|
||||||
|
const char *ty_name = fx_type_get_name(ty);
|
||||||
|
bshell_command_class *cmd = fx_type_get_interface(
|
||||||
|
ty,
|
||||||
|
BSHELL_TYPE_COMMAND);
|
||||||
|
if (!cmd || !cmd->c_get_callable_name_static) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_string_clear(target_name);
|
||||||
|
cmd->c_get_callable_name_static(ty, target_name);
|
||||||
|
|
||||||
|
if (!fx_strcmp_nocase(
|
||||||
|
fx_string_get_cstr(call_name),
|
||||||
|
fx_string_get_cstr(target_name))) {
|
||||||
|
return fx_object_create(fx_type_get_id(ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_command_set_args(
|
||||||
|
bshell_command *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_V(
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
command_set_args,
|
||||||
|
cmd,
|
||||||
|
args,
|
||||||
|
nr_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_command_set_args_reverse(
|
||||||
|
bshell_command *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_V(
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
command_set_args_reverse,
|
||||||
|
cmd,
|
||||||
|
args,
|
||||||
|
nr_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fx_value *bshell_command_get_arg(bshell_command *cmd, size_t index)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
command_get_arg,
|
||||||
|
cmd,
|
||||||
|
index);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_command_begin_processing(bshell_command *command)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_VIRTUAL_0(
|
||||||
|
bshell_command,
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
BSHELL_ERR_NOT_SUPPORTED,
|
||||||
|
c_begin_processing,
|
||||||
|
command);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_command_process_record(
|
||||||
|
bshell_command *command,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_VIRTUAL(
|
||||||
|
bshell_command,
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
BSHELL_ERR_NOT_SUPPORTED,
|
||||||
|
c_process_record,
|
||||||
|
command,
|
||||||
|
pipeline,
|
||||||
|
rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_command_end_processing(bshell_command *command)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_VIRTUAL_0(
|
||||||
|
bshell_command,
|
||||||
|
BSHELL_TYPE_COMMAND,
|
||||||
|
BSHELL_ERR_NOT_SUPPORTED,
|
||||||
|
c_end_processing,
|
||||||
|
command);
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_command)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_PROPERTY("command_type", get_command_type, NULL);
|
||||||
|
FX_TYPE_PROPERTY("name", get_name, NULL);
|
||||||
|
FX_TYPE_PROPERTY("version", get_version, NULL);
|
||||||
|
FX_TYPE_PROPERTY("source", get_source, NULL);
|
||||||
|
FX_TYPE_CLASS_END(bshell_command)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_command)
|
||||||
|
FX_TYPE_ID(0x5c50630d, 0x7535, 0x40ed, 0xbae5, 0x88aabc274d79);
|
||||||
|
FX_TYPE_NAME("bshell.command");
|
||||||
|
FX_TYPE_CLASS(bshell_command_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_command_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_command)
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef COMMAND_COMMAND_H_
|
||||||
|
#define COMMAND_COMMAND_H_
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/reflection/type.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_COMMAND (bshell_command_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_command);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_command)
|
||||||
|
const char *c_command_type;
|
||||||
|
enum bshell_status (
|
||||||
|
*c_get_callable_name)(const bshell_command *, fx_string *);
|
||||||
|
enum bshell_status (
|
||||||
|
*c_get_callable_name_static)(const fx_type *, fx_string *);
|
||||||
|
enum bshell_status (
|
||||||
|
*c_get_description)(const bshell_command *, fx_string *);
|
||||||
|
enum bshell_status (
|
||||||
|
*c_get_description_static)(const fx_type *, fx_string *);
|
||||||
|
enum bshell_status (*c_begin_processing)(bshell_command *);
|
||||||
|
enum bshell_status (*c_process_record)(
|
||||||
|
bshell_command *,
|
||||||
|
FX_TYPE_FWDREF(bshell_pipeline) * pipeline,
|
||||||
|
struct bshell_runtime *);
|
||||||
|
enum bshell_status (*c_end_processing)(bshell_command *);
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_command)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_command_get_type(void);
|
||||||
|
|
||||||
|
extern bshell_command *bshell_command_find_static(const char *callable_name);
|
||||||
|
|
||||||
|
extern void bshell_command_set_args(
|
||||||
|
bshell_command *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args);
|
||||||
|
extern void bshell_command_set_args_reverse(
|
||||||
|
bshell_command *cmd,
|
||||||
|
fx_value *args,
|
||||||
|
size_t nr_args);
|
||||||
|
extern const fx_value *bshell_command_get_arg(
|
||||||
|
bshell_command *cmd,
|
||||||
|
size_t index);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_command_begin_processing(
|
||||||
|
bshell_command *command);
|
||||||
|
extern enum bshell_status bshell_command_process_record(
|
||||||
|
bshell_command *command,
|
||||||
|
FX_TYPE_FWDREF(bshell_pipeline) * pipeline,
|
||||||
|
struct bshell_runtime *rt);
|
||||||
|
extern enum bshell_status bshell_command_end_processing(
|
||||||
|
bshell_command *command);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef COMMAND_FUNCTION_H_
|
||||||
|
#define COMMAND_FUNCTION_H_
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_FUNCTION (bshell_function_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_function);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_function)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_function)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_function_get_type(void);
|
||||||
|
|
||||||
|
extern bshell_function *bshell_function_create(const char *name);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef COMPILE_H_
|
||||||
|
#define COMPILE_H_
|
||||||
|
|
||||||
|
#include "script-block.h"
|
||||||
|
|
||||||
|
struct ast_node;
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_compile(
|
||||||
|
struct ast_node *src,
|
||||||
|
bshell_scriptblock *dest);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static const struct compile_value_type array_type = {};
|
||||||
|
static const struct compile_value_type array_item_type = {};
|
||||||
|
|
||||||
|
struct compile_result compile_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct array_ast_node *array = (struct array_ast_node *)src;
|
||||||
|
size_t nr_items = fx_queue_length(&array->n_items);
|
||||||
|
for (size_t i = 0; i < nr_items; i++) {
|
||||||
|
struct compile_value *item = compile_pop_value(ctx);
|
||||||
|
compile_value_load(ctx, item);
|
||||||
|
compile_value_destroy(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_MK_ARRAY,
|
||||||
|
nr_items);
|
||||||
|
compile_push_value(ctx, &array_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "../compile.h"
|
||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static enum bshell_status block_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDBLOCK,
|
||||||
|
value->v_pool);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type block_type = {
|
||||||
|
.v_load = block_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_block(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
bshell_scriptblock *sub_block = bshell_scriptblock_create();
|
||||||
|
if (!sub_block) {
|
||||||
|
return COMPILE_ERR(BSHELL_ERR_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status status = bshell_compile(src, sub_block);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
bshell_scriptblock_unref(sub_block);
|
||||||
|
return COMPILE_ERR(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value sub_block_value = FX_VALUE_OBJECT(sub_block);
|
||||||
|
unsigned long slot = bshell_scriptblock_add_pool_value(
|
||||||
|
ctx->c_block,
|
||||||
|
&sub_block_value);
|
||||||
|
fx_value_unset(&sub_block_value);
|
||||||
|
compile_push_pool_value(ctx, &block_type, slot);
|
||||||
|
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_block_immediate(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
struct block_ast_node *block = (struct block_ast_node *)src;
|
||||||
|
|
||||||
|
fx_queue_entry *cur = fx_queue_first(&block->n_statements);
|
||||||
|
while (cur && status == BSHELL_SUCCESS) {
|
||||||
|
struct ast_node *node = fx_unbox(struct ast_node, cur, n_entry);
|
||||||
|
status = compile_node(ctx, node);
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status cmdcall_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_PEXEC, 1);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status pipeline_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
size_t nr_items = fx_queue_length(&pipeline->n_stages);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_PEXEC,
|
||||||
|
nr_items);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type cmdcall_type = {
|
||||||
|
.v_load = cmdcall_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct compile_value_type pipeline_type = {
|
||||||
|
.v_load = pipeline_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_cmdcall(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct cmdcall_ast_node *cmdcall = (struct cmdcall_ast_node *)src;
|
||||||
|
size_t nr_args = fx_queue_length(&cmdcall->n_args);
|
||||||
|
for (size_t i = 0; i < nr_args; i++) {
|
||||||
|
struct compile_value *arg = compile_pop_value(ctx);
|
||||||
|
compile_value_load(ctx, arg);
|
||||||
|
compile_value_destroy(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDCMD,
|
||||||
|
nr_args);
|
||||||
|
|
||||||
|
compile_push_value(ctx, &cmdcall_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_pipeline(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct pipeline_ast_node *pipeline = (struct pipeline_ast_node *)src;
|
||||||
|
size_t nr_items = fx_queue_length(&pipeline->n_stages);
|
||||||
|
for (size_t i = 0; i < nr_items; i++) {
|
||||||
|
struct compile_value *item = compile_pop_value(ctx);
|
||||||
|
if (item->v_node->n_type != AST_CMDCALL) {
|
||||||
|
compile_value_load(ctx, item);
|
||||||
|
}
|
||||||
|
compile_value_destroy(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_push_value(ctx, &pipeline_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
#ifndef COMPILE_COMPILE_NODE_H_
|
||||||
|
#define COMPILE_COMPILE_NODE_H_
|
||||||
|
|
||||||
|
#include "../ast/ast.h"
|
||||||
|
#include "../operator.h"
|
||||||
|
#include "../parse/token.h"
|
||||||
|
#include "../script-block.h"
|
||||||
|
|
||||||
|
#include <fx/queue.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
#define COMPILE_OK(flags) \
|
||||||
|
((struct compile_result) {.r_status = BSHELL_SUCCESS, \
|
||||||
|
.r_flags = (flags)})
|
||||||
|
#define COMPILE_ERR(status) ((struct compile_result) {.r_status = (status)})
|
||||||
|
|
||||||
|
struct compile_ctx;
|
||||||
|
struct compile_value;
|
||||||
|
|
||||||
|
struct compile_result {
|
||||||
|
enum bshell_status r_status;
|
||||||
|
enum {
|
||||||
|
COMPILE_REPEAT_NODE = 0x00u,
|
||||||
|
} r_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct compile_result (*compile_begin_impl)(struct compile_ctx *);
|
||||||
|
typedef struct compile_result (*compile_end_impl)(struct compile_ctx *);
|
||||||
|
typedef struct compile_result (
|
||||||
|
*compile_node_impl)(struct compile_ctx *, struct ast_node *);
|
||||||
|
|
||||||
|
enum compile_state_type_id {
|
||||||
|
COMPILE_NORMAL = 0,
|
||||||
|
COMPILE_FSTRING,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_value_type {
|
||||||
|
enum bshell_status (
|
||||||
|
*v_load)(struct compile_ctx *, struct compile_value *);
|
||||||
|
enum bshell_status (
|
||||||
|
*v_store)(struct compile_ctx *, struct compile_value *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_value {
|
||||||
|
const struct compile_value_type *v_type;
|
||||||
|
enum operator_id v_op;
|
||||||
|
struct compile_value *v_left, *v_right;
|
||||||
|
struct compile_value **v_args;
|
||||||
|
size_t v_nr_args;
|
||||||
|
struct ast_node *v_node;
|
||||||
|
unsigned long v_pool;
|
||||||
|
fx_queue_entry v_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_label {
|
||||||
|
size_t l_ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_label_ref {
|
||||||
|
fx_queue_entry ref_entry;
|
||||||
|
size_t ref_offset;
|
||||||
|
size_t ref_label_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_ctx {
|
||||||
|
fx_queue c_state, c_stack;
|
||||||
|
bshell_scriptblock *c_block;
|
||||||
|
FX_VECTOR_DECLARE(struct compile_label, c_labels);
|
||||||
|
fx_queue c_label_refs;
|
||||||
|
size_t c_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_state_type {
|
||||||
|
size_t s_size;
|
||||||
|
compile_begin_impl s_compile_begin;
|
||||||
|
compile_end_impl s_compile_end;
|
||||||
|
const compile_node_impl *s_compile_node;
|
||||||
|
compile_node_impl s_compile_node_generic;
|
||||||
|
size_t s_nr_compile_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_state {
|
||||||
|
const struct compile_state_type *s_type;
|
||||||
|
fx_queue_entry s_entry;
|
||||||
|
size_t s_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct compile_state *compile_push_state(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
enum compile_state_type_id state_type);
|
||||||
|
extern void compile_pop_state(struct compile_ctx *ctx);
|
||||||
|
extern struct compile_state *compile_get_state(const struct compile_ctx *ctx);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_push_value(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
struct ast_node *node);
|
||||||
|
extern enum bshell_status compile_push_value_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
struct ast_node *node,
|
||||||
|
struct compile_value **values,
|
||||||
|
size_t nr_values);
|
||||||
|
extern enum bshell_status compile_push_pool_value(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
unsigned long pool_slot);
|
||||||
|
extern enum bshell_status compile_push_op(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *node,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
enum operator_id op,
|
||||||
|
struct compile_value *left,
|
||||||
|
struct compile_value *right);
|
||||||
|
extern struct compile_value *compile_pop_value(struct compile_ctx *ctx);
|
||||||
|
extern void compile_value_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *item);
|
||||||
|
extern void compile_value_store(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *item);
|
||||||
|
extern void compile_value_destroy(struct compile_value *item);
|
||||||
|
|
||||||
|
extern size_t compile_declare_label(struct compile_ctx *ctx);
|
||||||
|
extern void compile_define_label(struct compile_ctx *ctx, size_t label_id);
|
||||||
|
extern void compile_ref_label(struct compile_ctx *ctx, size_t label_id);
|
||||||
|
extern enum bshell_status compile_resolve_labels(struct compile_ctx *ctx);
|
||||||
|
|
||||||
|
extern struct compile_result compile_int(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_double(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_string(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_word(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_op(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_var(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_fstring(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_hashtable_item(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_hashtable(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_block(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern struct compile_result compile_cmdcall(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern struct compile_result compile_pipeline(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_if(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_block_immediate(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
extern enum bshell_status compile_expression(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
extern enum bshell_status compile_node(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "../compile.h"
|
||||||
|
|
||||||
|
#include "../ast/ast.h"
|
||||||
|
#include "../debug.h"
|
||||||
|
#include "../status.h"
|
||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern enum bshell_status compile_node(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
switch (src->n_type) {
|
||||||
|
case AST_IF:
|
||||||
|
return compile_if(ctx, src);
|
||||||
|
case AST_BLOCK:
|
||||||
|
return compile_block_immediate(ctx, src);
|
||||||
|
default:
|
||||||
|
return compile_expression(ctx, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_compile(
|
||||||
|
struct ast_node *src,
|
||||||
|
bshell_scriptblock *dest)
|
||||||
|
{
|
||||||
|
struct compile_ctx ctx = {.c_block = dest};
|
||||||
|
|
||||||
|
enum bshell_status status = compile_node(&ctx, src);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = compile_resolve_labels(&ctx);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status int_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct int_ast_node *i = (struct int_ast_node *)value->v_node;
|
||||||
|
long long v;
|
||||||
|
fx_value_get_longlong(&i->n_value->tok_number, &v);
|
||||||
|
bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_LDC_INT, v);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status double_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct double_ast_node *d = (struct double_ast_node *)value->v_node;
|
||||||
|
double v;
|
||||||
|
fx_value_get_double(&d->n_value->tok_number, &v);
|
||||||
|
unsigned long index = bshell_scriptblock_get_double(ctx->c_block, v);
|
||||||
|
bshell_scriptblock_push_instruction(ctx->c_block, OPCODE_LDC_FP, index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status string_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct string_ast_node *s = (struct string_ast_node *)value->v_node;
|
||||||
|
unsigned long index = bshell_scriptblock_get_string(
|
||||||
|
ctx->c_block,
|
||||||
|
s->n_value->tok_str);
|
||||||
|
if (index == POOL_INDEX_INVALID) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDC_STR,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status word_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct word_ast_node *s = (struct word_ast_node *)value->v_node;
|
||||||
|
unsigned long index = bshell_scriptblock_get_string(
|
||||||
|
ctx->c_block,
|
||||||
|
s->n_value->tok_str);
|
||||||
|
if (index == POOL_INDEX_INVALID) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDC_STR,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type int_type = {
|
||||||
|
.v_load = int_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct compile_value_type double_type = {
|
||||||
|
.v_load = double_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct compile_value_type string_type = {
|
||||||
|
.v_load = string_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct compile_value_type word_type = {
|
||||||
|
.v_load = word_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_int(struct compile_ctx *ctx, struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &int_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_double(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &double_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_string(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &string_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_word(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &word_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static struct ast_iterate_result do_compile_node(
|
||||||
|
struct ast_node *node,
|
||||||
|
enum ast_iteration_type it_type,
|
||||||
|
struct ast_iterator *it,
|
||||||
|
struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (it_type != AST_ITERATION_POST) {
|
||||||
|
int flags = 0;
|
||||||
|
switch (node->n_type) {
|
||||||
|
case AST_BLOCK:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags |= AST_ITERATE_ADD_CHILDREN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_ITERATE_OK(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->c_depth = node->n_it.e_depth;
|
||||||
|
struct compile_state *state = compile_get_state(ctx);
|
||||||
|
while (state->s_depth >= ctx->c_depth && state->s_depth > 0) {
|
||||||
|
compile_pop_state(ctx);
|
||||||
|
state = compile_get_state(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_node_impl impl = NULL;
|
||||||
|
|
||||||
|
if (node->n_type < state->s_type->s_nr_compile_node) {
|
||||||
|
impl = state->s_type->s_compile_node[node->n_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!impl) {
|
||||||
|
impl = state->s_type->s_compile_node_generic;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!impl) {
|
||||||
|
return AST_ITERATE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result result = impl(ctx, node);
|
||||||
|
unsigned int flags = 0;
|
||||||
|
if (result.r_flags & COMPILE_REPEAT_NODE) {
|
||||||
|
flags |= AST_ITERATE_REPEAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.r_status == BSHELL_SUCCESS) {
|
||||||
|
return AST_ITERATE_OK(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AST_ITERATE_ERR(result.r_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_expression(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_state(ctx, COMPILE_NORMAL);
|
||||||
|
|
||||||
|
struct ast_iterator it = {0};
|
||||||
|
ast_node_iterate(src, &it, (ast_iterator_callback)do_compile_node, ctx);
|
||||||
|
|
||||||
|
struct compile_value *result = compile_pop_value(ctx);
|
||||||
|
if (result) {
|
||||||
|
compile_value_load(ctx, result);
|
||||||
|
compile_value_destroy(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status fstring_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct fstring_ast_node *fstring = (struct fstring_ast_node *)
|
||||||
|
value->v_node;
|
||||||
|
for (size_t i = 0; i < value->v_nr_args; i++) {
|
||||||
|
compile_value_load(ctx, value->v_args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_MK_STR,
|
||||||
|
fx_queue_length(&fstring->n_elements));
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type fstring_type = {
|
||||||
|
.v_load = fstring_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_fstring(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct fstring_ast_node *fstring = (struct fstring_ast_node *)src;
|
||||||
|
size_t nr_items = fx_queue_length(&fstring->n_elements);
|
||||||
|
struct compile_value **items = calloc(nr_items, sizeof *items);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nr_items; i++) {
|
||||||
|
struct compile_value *item = compile_pop_value(ctx);
|
||||||
|
items[i] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_push_value_array(ctx, &fstring_type, src, items, nr_items);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static const struct compile_value_type hashtable_type = {};
|
||||||
|
static const struct compile_value_type hashtable_item_type = {};
|
||||||
|
|
||||||
|
struct compile_result compile_hashtable(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct hashtable_ast_node *hashtable = (struct hashtable_ast_node *)src;
|
||||||
|
size_t nr_items = fx_queue_length(&hashtable->n_items);
|
||||||
|
for (size_t i = 0; i < nr_items; i++) {
|
||||||
|
struct compile_value *item = compile_pop_value(ctx);
|
||||||
|
compile_value_load(ctx, item);
|
||||||
|
compile_value_destroy(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_MK_HTAB,
|
||||||
|
nr_items);
|
||||||
|
compile_push_value(ctx, &hashtable_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_result compile_hashtable_item(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct compile_value *value = compile_pop_value(ctx);
|
||||||
|
struct compile_value *key = compile_pop_value(ctx);
|
||||||
|
compile_value_load(ctx, key);
|
||||||
|
compile_value_load(ctx, value);
|
||||||
|
compile_value_destroy(key);
|
||||||
|
compile_value_destroy(value);
|
||||||
|
|
||||||
|
compile_push_value(ctx, &hashtable_item_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status compile_if(struct compile_ctx *ctx, struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct if_ast_node *if_group = (struct if_ast_node *)src;
|
||||||
|
size_t nr_labels = fx_queue_length(&if_group->n_branches);
|
||||||
|
// add one extra label for the end of the if group
|
||||||
|
nr_labels++;
|
||||||
|
|
||||||
|
size_t *label_ids = calloc(nr_labels, sizeof *label_ids);
|
||||||
|
if (!label_ids) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < nr_labels; i++) {
|
||||||
|
label_ids[i] = compile_declare_label(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
fx_queue_entry *cur = fx_queue_first(&if_group->n_branches);
|
||||||
|
while (cur) {
|
||||||
|
struct if_branch_ast_node *branch = fx_unbox(
|
||||||
|
struct if_branch_ast_node,
|
||||||
|
cur,
|
||||||
|
n_base.n_entry);
|
||||||
|
if (!branch->n_cond) {
|
||||||
|
compile_block_immediate(ctx, branch->n_body);
|
||||||
|
compile_ref_label(ctx, label_ids[nr_labels - 1]);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_BR,
|
||||||
|
0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_expression(ctx, branch->n_cond);
|
||||||
|
compile_ref_label(ctx, label_ids[i++]);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_BR_TRUE,
|
||||||
|
0);
|
||||||
|
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
cur = fx_queue_first(&if_group->n_branches);
|
||||||
|
while (cur) {
|
||||||
|
struct if_branch_ast_node *branch = fx_unbox(
|
||||||
|
struct if_branch_ast_node,
|
||||||
|
cur,
|
||||||
|
n_base.n_entry);
|
||||||
|
if (!branch->n_cond) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_define_label(ctx, label_ids[i++]);
|
||||||
|
compile_block_immediate(ctx, branch->n_body);
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
|
||||||
|
if (i < nr_labels - 2) {
|
||||||
|
compile_ref_label(ctx, label_ids[nr_labels - 1]);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_BR,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_define_label(ctx, label_ids[nr_labels - 1]);
|
||||||
|
free(label_ids);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
size_t compile_declare_label(struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
size_t id = ctx->c_labels.count;
|
||||||
|
struct compile_label *label = fx_vector_emplace_back(
|
||||||
|
ctx->c_labels,
|
||||||
|
NULL);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_define_label(struct compile_ctx *ctx, size_t label_id)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
bshell_scriptblock_get_text(ctx->c_block, NULL, &offset);
|
||||||
|
offset *= sizeof(bshell_instruction);
|
||||||
|
ctx->c_labels.items[label_id].l_ip = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_ref_label(struct compile_ctx *ctx, size_t label_id)
|
||||||
|
{
|
||||||
|
struct compile_label_ref *ref = malloc(sizeof *ref);
|
||||||
|
if (!ref) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(ref, 0x0, sizeof *ref);
|
||||||
|
ref->ref_label_id = label_id;
|
||||||
|
bshell_scriptblock_get_text(ctx->c_block, NULL, &ref->ref_offset);
|
||||||
|
ref->ref_offset *= sizeof(bshell_instruction);
|
||||||
|
fx_queue_push_back(&ctx->c_label_refs, &ref->ref_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_resolve_labels(struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
fx_queue_entry *cur = fx_queue_pop_front(&ctx->c_label_refs);
|
||||||
|
while (cur) {
|
||||||
|
struct compile_label_ref *ref = fx_unbox(
|
||||||
|
struct compile_label_ref,
|
||||||
|
cur,
|
||||||
|
ref_entry);
|
||||||
|
struct compile_label *label = &ctx->c_labels.items
|
||||||
|
[ref->ref_label_id];
|
||||||
|
|
||||||
|
long long rel_value = (long long)label->l_ip
|
||||||
|
- (long long)ref->ref_offset;
|
||||||
|
|
||||||
|
enum bshell_opcode op;
|
||||||
|
uint32_t arg;
|
||||||
|
bshell_scriptblock_read_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
ref->ref_offset,
|
||||||
|
&op,
|
||||||
|
&arg);
|
||||||
|
arg = (uint32_t)rel_value;
|
||||||
|
bshell_scriptblock_patch_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
ref->ref_offset,
|
||||||
|
op,
|
||||||
|
arg);
|
||||||
|
|
||||||
|
free(ref);
|
||||||
|
cur = fx_queue_pop_front(&ctx->c_label_refs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static const compile_node_impl node_compilers[] = {
|
||||||
|
[AST_INT] = compile_int,
|
||||||
|
[AST_DOUBLE] = compile_double,
|
||||||
|
[AST_STRING] = compile_string,
|
||||||
|
[AST_WORD] = compile_word,
|
||||||
|
[AST_OP] = compile_op,
|
||||||
|
[AST_VAR] = compile_var,
|
||||||
|
[AST_FSTRING] = compile_fstring,
|
||||||
|
[AST_ARRAY] = compile_array,
|
||||||
|
[AST_HASHTABLE] = compile_hashtable,
|
||||||
|
[AST_HASHTABLE_ITEM] = compile_hashtable_item,
|
||||||
|
[AST_CMDCALL] = compile_cmdcall,
|
||||||
|
[AST_PIPELINE] = compile_pipeline,
|
||||||
|
[AST_BLOCK] = compile_block,
|
||||||
|
};
|
||||||
|
static const size_t nr_node_compilers = sizeof node_compilers
|
||||||
|
/ sizeof node_compilers[0];
|
||||||
|
|
||||||
|
const struct compile_state_type normal_state = {
|
||||||
|
.s_size = sizeof(struct compile_state),
|
||||||
|
.s_compile_node = node_compilers,
|
||||||
|
.s_nr_compile_node = nr_node_compilers,
|
||||||
|
};
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#include "../operator.h"
|
||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
static enum bshell_opcode opcode_for_op(enum operator_id op)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case OP_ADD:
|
||||||
|
return OPCODE_ADD;
|
||||||
|
case OP_SUBTRACT:
|
||||||
|
return OPCODE_SUB;
|
||||||
|
case OP_MULTIPLY:
|
||||||
|
return OPCODE_MUL;
|
||||||
|
case OP_DIVIDE:
|
||||||
|
return OPCODE_DIV;
|
||||||
|
case OP_MODULO:
|
||||||
|
return OPCODE_MOD;
|
||||||
|
case OP_INCREMENT:
|
||||||
|
return OPCODE_INC;
|
||||||
|
case OP_DECREMENT:
|
||||||
|
return OPCODE_DEC;
|
||||||
|
case OP_LEFT_SHIFT:
|
||||||
|
return OPCODE_SHL;
|
||||||
|
case OP_RIGHT_SHIFT:
|
||||||
|
return OPCODE_SHR;
|
||||||
|
case OP_BINARY_AND:
|
||||||
|
return OPCODE_BAND;
|
||||||
|
case OP_BINARY_OR:
|
||||||
|
return OPCODE_BOR;
|
||||||
|
case OP_BINARY_XOR:
|
||||||
|
return OPCODE_BXOR;
|
||||||
|
case OP_BINARY_NOT:
|
||||||
|
return OPCODE_BNOT;
|
||||||
|
case OP_LESS_THAN:
|
||||||
|
return OPCODE_CMP_LT;
|
||||||
|
case OP_GREATER_THAN:
|
||||||
|
return OPCODE_CMP_GT;
|
||||||
|
case OP_EQUAL:
|
||||||
|
return OPCODE_CMP_EQ;
|
||||||
|
case OP_NOT_EQUAL:
|
||||||
|
return OPCODE_CMP_NE;
|
||||||
|
case OP_LESS_EQUAL:
|
||||||
|
return OPCODE_CMP_LE;
|
||||||
|
case OP_GREATER_EQUAL:
|
||||||
|
return OPCODE_CMP_GE;
|
||||||
|
case OP_LOGICAL_AND:
|
||||||
|
return OPCODE_LAND;
|
||||||
|
case OP_LOGICAL_OR:
|
||||||
|
return OPCODE_LOR;
|
||||||
|
case OP_LOGICAL_XOR:
|
||||||
|
return OPCODE_LXOR;
|
||||||
|
case OP_LOGICAL_NOT:
|
||||||
|
return OPCODE_LNOT;
|
||||||
|
case OP_RANGE:
|
||||||
|
return OPCODE_RANGE;
|
||||||
|
case OP_MATCH:
|
||||||
|
return OPCODE_MATCH;
|
||||||
|
case OP_REPLACE:
|
||||||
|
return OPCODE_REPLACE;
|
||||||
|
case OP_LIKE:
|
||||||
|
return OPCODE_LIKE;
|
||||||
|
case OP_IN:
|
||||||
|
return OPCODE_IN;
|
||||||
|
case OP_FORMAT:
|
||||||
|
return OPCODE_FMT;
|
||||||
|
case OP_CONTAINS:
|
||||||
|
return OPCODE_CONTAINS;
|
||||||
|
case OP_USPLIT:
|
||||||
|
return OPCODE_SPLIT;
|
||||||
|
case OP_BSPLIT:
|
||||||
|
return OPCODE_SPLIT;
|
||||||
|
case OP_UJOIN:
|
||||||
|
return OPCODE_JOIN;
|
||||||
|
case OP_BJOIN:
|
||||||
|
return OPCODE_JOIN;
|
||||||
|
case OP_IS:
|
||||||
|
return OPCODE_IS;
|
||||||
|
case OP_AS:
|
||||||
|
return OPCODE_AS;
|
||||||
|
case OP_ACCESS:
|
||||||
|
return OPCODE_LDPROP;
|
||||||
|
default:
|
||||||
|
return OPCODE_NOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status op_load(struct compile_ctx *ctx, struct compile_value *value)
|
||||||
|
{
|
||||||
|
enum bshell_opcode opcode = opcode_for_op(value->v_op);
|
||||||
|
if (opcode != OPCODE_NOP) {
|
||||||
|
compile_value_load(ctx, value->v_right);
|
||||||
|
compile_value_load(ctx, value->v_left);
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
opcode_for_op(value->v_op),
|
||||||
|
0);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (value->v_op) {
|
||||||
|
case OP_ASSIGN:
|
||||||
|
compile_value_load(ctx, value->v_right);
|
||||||
|
compile_value_store(ctx, value->v_left);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type op_type = {
|
||||||
|
.v_load = op_load,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_op(struct compile_ctx *ctx, struct ast_node *src)
|
||||||
|
{
|
||||||
|
struct op_ast_node *op = (struct op_ast_node *)src;
|
||||||
|
struct compile_value *left = NULL, *right = NULL;
|
||||||
|
left = compile_pop_value(ctx);
|
||||||
|
right = compile_pop_value(ctx);
|
||||||
|
compile_push_op(ctx, src, &op_type, op->n_op->op_id, left, right);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status compile_push_value(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
struct ast_node *node)
|
||||||
|
{
|
||||||
|
struct compile_value *item = malloc(sizeof *item);
|
||||||
|
if (!item) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(item, 0x0, sizeof *item);
|
||||||
|
|
||||||
|
item->v_type = type;
|
||||||
|
item->v_node = node;
|
||||||
|
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_push_value_array(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
struct ast_node *node,
|
||||||
|
struct compile_value **values,
|
||||||
|
size_t nr_values)
|
||||||
|
{
|
||||||
|
struct compile_value *item = malloc(sizeof *item);
|
||||||
|
if (!item) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(item, 0x0, sizeof *item);
|
||||||
|
|
||||||
|
item->v_type = type;
|
||||||
|
item->v_node = node;
|
||||||
|
item->v_args = values;
|
||||||
|
item->v_nr_args = nr_values;
|
||||||
|
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_push_pool_value(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
unsigned long pool_slot)
|
||||||
|
{
|
||||||
|
struct compile_value *item = malloc(sizeof *item);
|
||||||
|
if (!item) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(item, 0x0, sizeof *item);
|
||||||
|
|
||||||
|
item->v_type = type;
|
||||||
|
item->v_pool = pool_slot;
|
||||||
|
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status compile_push_op(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct ast_node *node,
|
||||||
|
const struct compile_value_type *type,
|
||||||
|
enum operator_id op,
|
||||||
|
struct compile_value *left,
|
||||||
|
struct compile_value *right)
|
||||||
|
{
|
||||||
|
struct compile_value *item = malloc(sizeof *item);
|
||||||
|
if (!item) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(item, 0x0, sizeof *item);
|
||||||
|
|
||||||
|
item->v_type = type;
|
||||||
|
item->v_node = node;
|
||||||
|
item->v_op = op;
|
||||||
|
item->v_left = left;
|
||||||
|
item->v_right = right;
|
||||||
|
fx_queue_push_back(&ctx->c_stack, &item->v_entry);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_value *compile_pop_value(struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
fx_queue_entry *entry = fx_queue_pop_back(&ctx->c_stack);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx_unbox(struct compile_value, entry, v_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_value_load(struct compile_ctx *ctx, struct compile_value *item)
|
||||||
|
{
|
||||||
|
if (item->v_type->v_load) {
|
||||||
|
item->v_type->v_load(ctx, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_value_store(struct compile_ctx *ctx, struct compile_value *item)
|
||||||
|
{
|
||||||
|
if (item->v_type->v_store) {
|
||||||
|
item->v_type->v_store(ctx, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_value_destroy(struct compile_value *value)
|
||||||
|
{
|
||||||
|
if (value->v_left) {
|
||||||
|
compile_value_destroy(value->v_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value->v_right) {
|
||||||
|
compile_value_destroy(value->v_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < value->v_nr_args; i++) {
|
||||||
|
compile_value_destroy(value->v_args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value->v_args) {
|
||||||
|
free(value->v_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
extern const struct compile_state_type normal_state;
|
||||||
|
static const struct compile_state_type *state_types[] = {
|
||||||
|
[COMPILE_NORMAL] = &normal_state,
|
||||||
|
};
|
||||||
|
static const size_t nr_state_types = sizeof state_types / sizeof state_types[0];
|
||||||
|
|
||||||
|
struct compile_state *compile_push_state(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
enum compile_state_type_id state_type_id)
|
||||||
|
{
|
||||||
|
if (state_type_id >= nr_state_types) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct compile_state_type *state_type = state_types
|
||||||
|
[state_type_id];
|
||||||
|
if (!state_type) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_state *state = malloc(state_type->s_size);
|
||||||
|
if (!state) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->s_type = state_type;
|
||||||
|
state->s_depth = ctx->c_depth;
|
||||||
|
fx_queue_push_back(&ctx->c_state, &state->s_entry);
|
||||||
|
|
||||||
|
if (state_type->s_compile_begin) {
|
||||||
|
state_type->s_compile_begin(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_pop_state(struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct compile_state *state = compile_get_state(ctx);
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fx_queue_prev(&state->s_entry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->s_type->s_compile_end) {
|
||||||
|
state->s_type->s_compile_end(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_queue_pop_back(&ctx->c_state);
|
||||||
|
free(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compile_state *compile_get_state(const struct compile_ctx *ctx)
|
||||||
|
{
|
||||||
|
fx_queue_entry *entry = fx_queue_last(&ctx->c_state);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx_unbox(struct compile_state, entry, s_entry);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#include "compile-node.h"
|
||||||
|
|
||||||
|
enum bshell_status var_load(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct var_ast_node *var = (struct var_ast_node *)value->v_node;
|
||||||
|
unsigned long index = bshell_scriptblock_get_string(
|
||||||
|
ctx->c_block,
|
||||||
|
var->n_ident->tok_str);
|
||||||
|
if (index == POOL_INDEX_INVALID) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_LDLOCAL,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status var_store(
|
||||||
|
struct compile_ctx *ctx,
|
||||||
|
struct compile_value *value)
|
||||||
|
{
|
||||||
|
struct var_ast_node *var = (struct var_ast_node *)value->v_node;
|
||||||
|
unsigned long index = bshell_scriptblock_get_string(
|
||||||
|
ctx->c_block,
|
||||||
|
var->n_ident->tok_str);
|
||||||
|
if (index == POOL_INDEX_INVALID) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_scriptblock_push_instruction(
|
||||||
|
ctx->c_block,
|
||||||
|
OPCODE_STLOCAL,
|
||||||
|
index);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct compile_value_type var_type = {
|
||||||
|
.v_load = var_load,
|
||||||
|
.v_store = var_store,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compile_result compile_var(struct compile_ctx *ctx, struct ast_node *src)
|
||||||
|
{
|
||||||
|
compile_push_value(ctx, &var_type, src);
|
||||||
|
return COMPILE_OK(0);
|
||||||
|
}
|
||||||
+327
-12
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "ast/ast.h"
|
#include "ast/ast.h"
|
||||||
#include "parse/token.h"
|
#include "parse/token.h"
|
||||||
|
#include "runtime/opcode.h"
|
||||||
|
#include "script-block.h"
|
||||||
|
|
||||||
#include <fx/string.h>
|
#include <fx/string.h>
|
||||||
#include <fx/term/print.h>
|
#include <fx/term/print.h>
|
||||||
@@ -68,10 +70,10 @@ extern void print_lex_token(struct lex_token *tok)
|
|||||||
printf("(%s)", token_keyword_to_string(tok->tok_keyword));
|
printf("(%s)", token_keyword_to_string(tok->tok_keyword));
|
||||||
break;
|
break;
|
||||||
case TOK_INT:
|
case TOK_INT:
|
||||||
printf("(%lld)", tok->tok_int);
|
|
||||||
break;
|
|
||||||
case TOK_DOUBLE:
|
case TOK_DOUBLE:
|
||||||
printf("(%lf)", tok->tok_double);
|
printf("(");
|
||||||
|
fx_value_to_string(&tok->tok_number, fx_stdout, NULL);
|
||||||
|
printf(")");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -82,15 +84,6 @@ extern void print_lex_token(struct lex_token *tok)
|
|||||||
|
|
||||||
void print_ast_node(struct ast_node *node)
|
void print_ast_node(struct ast_node *node)
|
||||||
{
|
{
|
||||||
struct ast_iterator it = {0};
|
|
||||||
ast_node_iterate(node, &it);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
node = ast_iterator_peek(&it);
|
|
||||||
if (!node) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned long i = 0; i < node->n_it.e_depth; i++) {
|
for (unsigned long i = 0; i < node->n_it.e_depth; i++) {
|
||||||
fx_puts(" ");
|
fx_puts(" ");
|
||||||
}
|
}
|
||||||
@@ -143,7 +136,329 @@ void print_ast_node(struct ast_node *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fx_printf("[reset]\n");
|
fx_printf("[reset]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_ast_node_recursive(struct ast_node *node)
|
||||||
|
{
|
||||||
|
struct ast_iterator it = {0};
|
||||||
|
ast_iterator_enqueue(&it, node);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
node = ast_iterator_peek(&it);
|
||||||
|
if (!node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_ast_node(node);
|
||||||
ast_iterator_dequeue(&it);
|
ast_iterator_dequeue(&it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_scriptblock(bshell_scriptblock *block, size_t depth)
|
||||||
|
{
|
||||||
|
bshell_instruction *instr = NULL;
|
||||||
|
size_t nr_instr = 0;
|
||||||
|
|
||||||
|
bshell_scriptblock_get_text(block, &instr, &nr_instr);
|
||||||
|
for (size_t i = 0; i < nr_instr; i++) {
|
||||||
|
size_t offset = i * sizeof *instr;
|
||||||
|
for (size_t ii = 0; ii < depth; ii++) {
|
||||||
|
fputs("| ", stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%04zx: ", offset);
|
||||||
|
print_instruction(offset, instr[i], block, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_instruction(
|
||||||
|
size_t offset,
|
||||||
|
bshell_instruction instr,
|
||||||
|
bshell_scriptblock *container,
|
||||||
|
size_t depth)
|
||||||
|
{
|
||||||
|
enum bshell_opcode opcode = 0;
|
||||||
|
uint32_t arg = 0;
|
||||||
|
fx_value *pool_value = NULL;
|
||||||
|
fx_object *obj;
|
||||||
|
double d;
|
||||||
|
const char *s = NULL;
|
||||||
|
|
||||||
|
bshell_instruction_decode(instr, &opcode, &arg);
|
||||||
|
|
||||||
|
fx_printf("%08x [blue]", instr);
|
||||||
|
switch (opcode) {
|
||||||
|
case OPCODE_LDC_INT:
|
||||||
|
fx_printf("ldc.int [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDC_FP:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_DOUBLE);
|
||||||
|
fx_printf("ldc.fp [cyan]@0x%02x ", arg);
|
||||||
|
if (pool_value) {
|
||||||
|
fx_value_get_double(pool_value, &d);
|
||||||
|
fx_printf("[reset][[[yellow]%g[reset]]", d);
|
||||||
|
} else {
|
||||||
|
fx_printf("[red]<INVALID>[reset]");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDC_STR:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_STRING);
|
||||||
|
if (!pool_value) {
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_CSTR);
|
||||||
|
}
|
||||||
|
fx_printf("ldc.str [cyan]@0x%02x ", arg);
|
||||||
|
if (pool_value) {
|
||||||
|
fx_value_get_cstr(pool_value, &s);
|
||||||
|
fx_printf("[reset][[[green]%s[reset]]", s);
|
||||||
|
} else {
|
||||||
|
fx_printf("[red]<INVALID>[reset]");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDGLOBAL:
|
||||||
|
fx_printf("ldglobal [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDBLOCK:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK);
|
||||||
|
fx_printf("ldblock [cyan]@0x%02x ", arg);
|
||||||
|
if (pool_value) {
|
||||||
|
fx_printf("[reset][[[magenta]vvv[reset]]\n");
|
||||||
|
fx_value_get_object(pool_value, &obj);
|
||||||
|
print_scriptblock(obj, depth + 1);
|
||||||
|
} else {
|
||||||
|
fx_printf("[red]<INVALID>[reset]");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDLOCAL:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_STRING);
|
||||||
|
if (!pool_value) {
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_CSTR);
|
||||||
|
}
|
||||||
|
fx_printf("ldlocal [cyan]@0x%02x ", arg);
|
||||||
|
if (pool_value) {
|
||||||
|
fx_value_get_cstr(pool_value, &s);
|
||||||
|
fx_printf("[reset][[[green]%s[reset]]", s);
|
||||||
|
} else {
|
||||||
|
fx_printf("[red]<INVALID>");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDENV:
|
||||||
|
fx_printf("ldenv [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDSTATIC:
|
||||||
|
fx_printf("ldstatic [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDARG:
|
||||||
|
fx_printf("ldarg [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDPROP:
|
||||||
|
fx_printf("ldprop");
|
||||||
|
break;
|
||||||
|
case OPCODE_LDELEM:
|
||||||
|
fx_printf("ldelem [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDELEM_C:
|
||||||
|
fx_printf("ldelem.c [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_STLOCAL:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_STRING);
|
||||||
|
if (!pool_value) {
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
container,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_CSTR);
|
||||||
|
}
|
||||||
|
fx_printf("stlocal [cyan]@0x%02x ", arg);
|
||||||
|
if (pool_value) {
|
||||||
|
fx_value_get_cstr(pool_value, &s);
|
||||||
|
fx_printf("[reset][[[green]%s[reset]]", s);
|
||||||
|
} else {
|
||||||
|
fx_printf("<INVALID>");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_STPROP:
|
||||||
|
fx_printf("stprop [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_STELEM:
|
||||||
|
fx_printf("stelem [cyan]@0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDCMD:
|
||||||
|
fx_printf("ldcmd [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_PEXEC:
|
||||||
|
fx_printf("pexec [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_CALL:
|
||||||
|
fx_printf("call");
|
||||||
|
break;
|
||||||
|
case OPCODE_MK_STR:
|
||||||
|
fx_printf("mk.str [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_MK_ARRAY:
|
||||||
|
fx_printf("mk.array [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_MK_HTAB:
|
||||||
|
fx_printf("mk.htab [yellow]#0x%02x", arg);
|
||||||
|
break;
|
||||||
|
case OPCODE_POP:
|
||||||
|
fx_printf("pop");
|
||||||
|
break;
|
||||||
|
case OPCODE_ADD:
|
||||||
|
fx_printf("add");
|
||||||
|
break;
|
||||||
|
case OPCODE_SUB:
|
||||||
|
fx_printf("sub");
|
||||||
|
break;
|
||||||
|
case OPCODE_MUL:
|
||||||
|
fx_printf("mul");
|
||||||
|
break;
|
||||||
|
case OPCODE_DIV:
|
||||||
|
fx_printf("div");
|
||||||
|
break;
|
||||||
|
case OPCODE_ADD_IP:
|
||||||
|
fx_printf("add.ip");
|
||||||
|
break;
|
||||||
|
case OPCODE_MOD:
|
||||||
|
fx_printf("mod");
|
||||||
|
break;
|
||||||
|
case OPCODE_INC:
|
||||||
|
fx_printf("inc");
|
||||||
|
break;
|
||||||
|
case OPCODE_DEC:
|
||||||
|
fx_printf("dec");
|
||||||
|
break;
|
||||||
|
case OPCODE_SHL:
|
||||||
|
fx_printf("shl");
|
||||||
|
break;
|
||||||
|
case OPCODE_SHR:
|
||||||
|
fx_printf("shr");
|
||||||
|
break;
|
||||||
|
case OPCODE_BAND:
|
||||||
|
fx_printf("band");
|
||||||
|
break;
|
||||||
|
case OPCODE_BOR:
|
||||||
|
fx_printf("bor");
|
||||||
|
break;
|
||||||
|
case OPCODE_BXOR:
|
||||||
|
fx_printf("bxor");
|
||||||
|
break;
|
||||||
|
case OPCODE_BNOT:
|
||||||
|
fx_printf("bnot");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_NULL:
|
||||||
|
fx_printf("cmp.null");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_EQ:
|
||||||
|
fx_printf("cmp.eq");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_NE:
|
||||||
|
fx_printf("cmp.ne");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_LT:
|
||||||
|
fx_printf("cmp.lt");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_GT:
|
||||||
|
fx_printf("cmp.gt");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_LE:
|
||||||
|
fx_printf("cmp.le");
|
||||||
|
break;
|
||||||
|
case OPCODE_CMP_GE:
|
||||||
|
fx_printf("cmp.ge");
|
||||||
|
break;
|
||||||
|
case OPCODE_LAND:
|
||||||
|
fx_printf("land");
|
||||||
|
break;
|
||||||
|
case OPCODE_LOR:
|
||||||
|
fx_printf("lor");
|
||||||
|
break;
|
||||||
|
case OPCODE_LXOR:
|
||||||
|
fx_printf("lxor");
|
||||||
|
break;
|
||||||
|
case OPCODE_LNOT:
|
||||||
|
fx_printf("lnot");
|
||||||
|
break;
|
||||||
|
case OPCODE_BR:
|
||||||
|
fx_printf(
|
||||||
|
"br [yellow]#0x%04x [=%04llx]",
|
||||||
|
arg,
|
||||||
|
(long long)arg + (long long)offset);
|
||||||
|
break;
|
||||||
|
case OPCODE_BR_TRUE:
|
||||||
|
fx_printf(
|
||||||
|
"br.true [yellow]#0x%04x [=%04llx]",
|
||||||
|
arg,
|
||||||
|
(long long)arg + (long long)offset);
|
||||||
|
break;
|
||||||
|
case OPCODE_RANGE:
|
||||||
|
fx_printf("range");
|
||||||
|
break;
|
||||||
|
case OPCODE_MATCH:
|
||||||
|
fx_printf("match");
|
||||||
|
break;
|
||||||
|
case OPCODE_REPLACE:
|
||||||
|
fx_printf("replace");
|
||||||
|
break;
|
||||||
|
case OPCODE_LIKE:
|
||||||
|
fx_printf("like");
|
||||||
|
break;
|
||||||
|
case OPCODE_IN:
|
||||||
|
fx_printf("in");
|
||||||
|
break;
|
||||||
|
case OPCODE_FMT:
|
||||||
|
fx_printf("fmt");
|
||||||
|
break;
|
||||||
|
case OPCODE_CONTAINS:
|
||||||
|
fx_printf("contains");
|
||||||
|
break;
|
||||||
|
case OPCODE_SPLIT:
|
||||||
|
fx_printf("split");
|
||||||
|
break;
|
||||||
|
case OPCODE_JOIN:
|
||||||
|
fx_printf("join");
|
||||||
|
break;
|
||||||
|
case OPCODE_IS:
|
||||||
|
fx_printf("is");
|
||||||
|
break;
|
||||||
|
case OPCODE_AS:
|
||||||
|
fx_printf("as");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fx_printf("INVALID\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_printf("[reset]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_value(fx_value *val)
|
||||||
|
{
|
||||||
|
fx_printf("[yellow]");
|
||||||
|
fx_value_to_string(val, fx_stdout, NULL);
|
||||||
|
fx_printf("[reset]\n");
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#ifndef DEBUG_H_
|
#ifndef DEBUG_H_
|
||||||
#define DEBUG_H_
|
#define DEBUG_H_
|
||||||
|
|
||||||
|
#include "runtime/opcode.h"
|
||||||
|
#include "script-block.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct ast_node;
|
struct ast_node;
|
||||||
@@ -8,5 +11,13 @@ struct lex_token;
|
|||||||
|
|
||||||
extern void print_lex_token(struct lex_token *tok);
|
extern void print_lex_token(struct lex_token *tok);
|
||||||
extern void print_ast_node(struct ast_node *node);
|
extern void print_ast_node(struct ast_node *node);
|
||||||
|
extern void print_ast_node_recursive(struct ast_node *node);
|
||||||
|
extern void print_scriptblock(bshell_scriptblock *block, size_t depth);
|
||||||
|
extern void print_instruction(
|
||||||
|
size_t offset,
|
||||||
|
bshell_instruction instr,
|
||||||
|
bshell_scriptblock *container,
|
||||||
|
size_t depth);
|
||||||
|
extern void print_value(fx_value *val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+4
-2
@@ -27,13 +27,15 @@ static enum bshell_status get_row(
|
|||||||
size_t *nr_read)
|
size_t *nr_read)
|
||||||
{
|
{
|
||||||
struct file *f = (struct file *)src;
|
struct file *f = (struct file *)src;
|
||||||
size_t nr_rows = fx_array_size(f->f_lines);
|
size_t nr_rows = fx_array_get_size(f->f_lines);
|
||||||
|
|
||||||
if (row > nr_rows) {
|
if (row > nr_rows) {
|
||||||
return BSHELL_ERR_EOF;
|
return BSHELL_ERR_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_string *line = fx_array_at(f->f_lines, row - 1);
|
fx_value *line_v = fx_array_get_ref(f->f_lines, row - 1);
|
||||||
|
fx_string *line = NULL;
|
||||||
|
fx_value_get_object(line_v, &line);
|
||||||
|
|
||||||
const char *line_str = fx_string_get_cstr(line);
|
const char *line_str = fx_string_get_cstr(line);
|
||||||
size_t line_len = fx_string_get_size(line, FX_STRLEN_NORMAL);
|
size_t line_len = fx_string_get_size(line, FX_STRLEN_NORMAL);
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
static struct table_format_column command_table_columns[] = {
|
||||||
|
TABLE_COLUMN("command_type", "command_type", 13),
|
||||||
|
TABLE_COLUMN("name", "name", COL_WIDTH_INFINITE),
|
||||||
|
TABLE_COLUMN("version", "version", 12),
|
||||||
|
TABLE_COLUMN("source", "source", 35),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format command_table_format = {
|
||||||
|
.fmt_columns = command_table_columns,
|
||||||
|
.fmt_column_count = sizeof command_table_columns
|
||||||
|
/ sizeof command_table_columns[0],
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
#include <fx/term/print.h>
|
||||||
|
#include <fx/type.h>
|
||||||
|
#include <fx/value-type.h>
|
||||||
|
|
||||||
|
static void format_value_fallback(const fx_value *value, fx_stream *dest)
|
||||||
|
{
|
||||||
|
fx_printf("[yellow]");
|
||||||
|
fx_value_to_string(value, dest, NULL);
|
||||||
|
fx_printf("[reset]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status format_value_default(const fx_value *value, fx_stream *dest)
|
||||||
|
{
|
||||||
|
if (fx_type_is_value_type(value->v_type)) {
|
||||||
|
format_value_fallback(value, dest);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_object *object = NULL;
|
||||||
|
fx_value_get_object(value, &object);
|
||||||
|
enum bshell_status status = format_object_table(object, dest);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
format_value_fallback(value, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#ifndef FORMAT_H_
|
||||||
|
#define FORMAT_H_
|
||||||
|
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/namemap.h>
|
||||||
|
#include <fx/object.h>
|
||||||
|
#include <fx/queue.h>
|
||||||
|
#include <fx/reflection/property.h>
|
||||||
|
#include <fx/reflection/type.h>
|
||||||
|
#include <fx/stream.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
#define TABLE_COLUMN(display_name, property_name, width) \
|
||||||
|
{ \
|
||||||
|
.col_display_name = (display_name), \
|
||||||
|
.col_property_name = (property_name), \
|
||||||
|
.col_width = (width), \
|
||||||
|
}
|
||||||
|
#define COL_WIDTH_INFINITE ((size_t)-1)
|
||||||
|
|
||||||
|
struct table_format_column {
|
||||||
|
const char *col_display_name;
|
||||||
|
const char *col_property_name;
|
||||||
|
size_t col_width;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format {
|
||||||
|
fx_namemap_entry fmt_entry;
|
||||||
|
const struct table_format_column *fmt_columns;
|
||||||
|
size_t fmt_column_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format_ctx_column {
|
||||||
|
const char *col_title;
|
||||||
|
size_t col_width;
|
||||||
|
size_t col_title_chars_written;
|
||||||
|
const char *col_title_ptr;
|
||||||
|
const fx_property *col_property;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format_ctx {
|
||||||
|
const struct table_format *ctx_fmt;
|
||||||
|
struct table_format_ctx_column *ctx_columns;
|
||||||
|
size_t ctx_columns_count;
|
||||||
|
unsigned int ctx_tty_width;
|
||||||
|
size_t ctx_variable_columns_count;
|
||||||
|
fx_stream *ctx_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum bshell_status table_format_init(void);
|
||||||
|
extern const struct table_format *table_format_get_for_type(const fx_type *ty);
|
||||||
|
extern enum bshell_status format_object_table(
|
||||||
|
fx_object *object,
|
||||||
|
fx_stream *dest);
|
||||||
|
extern enum bshell_status format_value_default(
|
||||||
|
const fx_value *value,
|
||||||
|
fx_stream *dest);
|
||||||
|
|
||||||
|
extern enum bshell_status table_format_ctx_init(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
fx_stream *out);
|
||||||
|
extern enum bshell_status table_format_ctx_cleanup(
|
||||||
|
struct table_format_ctx *ctx);
|
||||||
|
extern enum bshell_status table_format_ctx_prepare_columns_from_format(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_type *record_type,
|
||||||
|
const struct table_format *fmt);
|
||||||
|
extern enum bshell_status table_format_ctx_prepare_columns_from_object(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_type *record_type);
|
||||||
|
extern enum bshell_status table_format_ctx_print_headers(
|
||||||
|
struct table_format_ctx *ctx);
|
||||||
|
extern enum bshell_status table_format_ctx_print_record(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_value *record);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
static struct table_format_column hashtable_table_columns[] = {
|
||||||
|
TABLE_COLUMN("key", "key", 37),
|
||||||
|
TABLE_COLUMN("value", "value", COL_WIDTH_INFINITE),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format hashtable_table_format = {
|
||||||
|
.fmt_columns = hashtable_table_columns,
|
||||||
|
.fmt_column_count = sizeof hashtable_table_columns
|
||||||
|
/ sizeof hashtable_table_columns[0],
|
||||||
|
};
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/iterator.h>
|
||||||
|
#include <fx/reflection/type.h>
|
||||||
|
#include <fx/stringstream.h>
|
||||||
|
#include <fx/term/print.h>
|
||||||
|
#include <fx/term/tty.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
static fx_namemap table_formats = FX_NAMEMAP_INIT;
|
||||||
|
|
||||||
|
extern struct table_format hashtable_table_format;
|
||||||
|
extern struct table_format verb_table_format;
|
||||||
|
extern struct table_format command_table_format;
|
||||||
|
|
||||||
|
enum bshell_status table_format_init(void)
|
||||||
|
{
|
||||||
|
fx_namemap_put(
|
||||||
|
&table_formats,
|
||||||
|
"fx.collections.hashtable",
|
||||||
|
&hashtable_table_format.fmt_entry);
|
||||||
|
fx_namemap_put(
|
||||||
|
&table_formats,
|
||||||
|
"bshell.verb",
|
||||||
|
&verb_table_format.fmt_entry);
|
||||||
|
fx_namemap_put(
|
||||||
|
&table_formats,
|
||||||
|
"bshell.command",
|
||||||
|
&command_table_format.fmt_entry);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct table_format *table_format_get_for_type(const fx_type *ty)
|
||||||
|
{
|
||||||
|
while (ty) {
|
||||||
|
const char *name = fx_type_get_name(ty);
|
||||||
|
fx_namemap_entry *entry = fx_namemap_get(&table_formats, name);
|
||||||
|
if (entry) {
|
||||||
|
return fx_unbox(struct table_format, entry, fmt_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty = fx_type_get_parent(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status format_object_table(fx_object *object, fx_stream *dest)
|
||||||
|
{
|
||||||
|
const fx_type *type = fx_type_get_by_id(fx_object_query_type(object));
|
||||||
|
if (!type) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct table_format *fmt = table_format_get_for_type(type);
|
||||||
|
if (!fmt) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct table_format_ctx ctx;
|
||||||
|
table_format_ctx_init(&ctx, dest);
|
||||||
|
fx_iterator *it = fx_iterator_begin(object);
|
||||||
|
if (!it) {
|
||||||
|
table_format_ctx_prepare_columns_from_format(
|
||||||
|
&ctx,
|
||||||
|
fx_type_get_by_id(fx_object_query_type(object)),
|
||||||
|
fmt);
|
||||||
|
table_format_ctx_print_headers(&ctx);
|
||||||
|
table_format_ctx_print_record(&ctx, &FX_VALUE_OBJECT(object));
|
||||||
|
} else {
|
||||||
|
fx_value first = fx_iterator_get_value(it);
|
||||||
|
if (first.v_type) {
|
||||||
|
table_format_ctx_prepare_columns_from_format(
|
||||||
|
&ctx,
|
||||||
|
fx_type_get_by_id(first.v_type),
|
||||||
|
fmt);
|
||||||
|
}
|
||||||
|
table_format_ctx_print_headers(&ctx);
|
||||||
|
fx_foreach(value, it)
|
||||||
|
{
|
||||||
|
table_format_ctx_print_record(&ctx, &value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table_format_ctx_cleanup(&ctx);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_init(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
fx_stream *out)
|
||||||
|
{
|
||||||
|
memset(ctx, 0x0, sizeof *ctx);
|
||||||
|
ctx->ctx_out = out;
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_cleanup(struct table_format_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->ctx_columns) {
|
||||||
|
free(ctx->ctx_columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(ctx, 0x0, sizeof *ctx);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_prepare_columns_from_format(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_type *record_type,
|
||||||
|
const struct table_format *fmt)
|
||||||
|
{
|
||||||
|
if (!fmt && !record_type) {
|
||||||
|
return BSHELL_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fmt) {
|
||||||
|
fmt = table_format_get_for_type(record_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fmt) {
|
||||||
|
return table_format_ctx_prepare_columns_from_object(
|
||||||
|
ctx,
|
||||||
|
record_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ctx_fmt = fmt;
|
||||||
|
struct table_format_ctx_column *columns = calloc(
|
||||||
|
fmt->fmt_column_count,
|
||||||
|
sizeof *columns);
|
||||||
|
|
||||||
|
if (!columns) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct table_format_column *column_defs = fmt->fmt_columns;
|
||||||
|
|
||||||
|
ctx->ctx_columns = columns;
|
||||||
|
ctx->ctx_columns_count = fmt->fmt_column_count;
|
||||||
|
|
||||||
|
fx_tty_get_dimensions(fx_stdtty, &ctx->ctx_tty_width, NULL);
|
||||||
|
if (!ctx->ctx_tty_width) {
|
||||||
|
ctx->ctx_tty_width = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ctx_variable_columns_count = 0;
|
||||||
|
|
||||||
|
unsigned int tty_width = ctx->ctx_tty_width;
|
||||||
|
for (size_t i = 0; i < fmt->fmt_column_count; i++) {
|
||||||
|
columns[i].col_property = fx_type_get_property(
|
||||||
|
record_type,
|
||||||
|
column_defs[i].col_property_name);
|
||||||
|
columns[i].col_title = column_defs[i].col_display_name;
|
||||||
|
columns[i].col_title_ptr = column_defs[i].col_display_name;
|
||||||
|
|
||||||
|
if (column_defs[i].col_width == COL_WIDTH_INFINITE) {
|
||||||
|
ctx->ctx_variable_columns_count++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column_defs[i].col_width <= tty_width) {
|
||||||
|
columns[i].col_width = column_defs[i].col_width;
|
||||||
|
tty_width -= columns[i].col_width;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
columns[i].col_width = tty_width;
|
||||||
|
tty_width = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fmt->fmt_column_count; i++) {
|
||||||
|
if (column_defs[i].col_width == COL_WIDTH_INFINITE) {
|
||||||
|
columns[i].col_width = tty_width
|
||||||
|
/ ctx->ctx_variable_columns_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_prepare_columns_from_object(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_type *record_type)
|
||||||
|
{
|
||||||
|
fx_array *properties = fx_array_create();
|
||||||
|
|
||||||
|
fx_iterator *it = fx_type_get_properties(record_type);
|
||||||
|
fx_foreach(prop_v, it)
|
||||||
|
{
|
||||||
|
fx_array_push_back(properties, prop_v);
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
size_t column_count = fx_array_get_size(properties);
|
||||||
|
if (!column_count) {
|
||||||
|
fx_array_unref(properties);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct table_format_ctx_column *columns = calloc(
|
||||||
|
column_count,
|
||||||
|
sizeof *columns);
|
||||||
|
|
||||||
|
if (!columns) {
|
||||||
|
fx_array_unref(properties);
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ctx_columns = columns;
|
||||||
|
ctx->ctx_columns_count = column_count;
|
||||||
|
|
||||||
|
fx_tty_get_dimensions(fx_stdtty, &ctx->ctx_tty_width, NULL);
|
||||||
|
if (!ctx->ctx_tty_width) {
|
||||||
|
ctx->ctx_tty_width = 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ctx_variable_columns_count = 0;
|
||||||
|
|
||||||
|
unsigned int tty_width = ctx->ctx_tty_width;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < column_count; i++) {
|
||||||
|
fx_value *prop_v = fx_array_get_ref(properties, i);
|
||||||
|
fx_property *prop = NULL;
|
||||||
|
fx_value_get_object(prop_v, &prop);
|
||||||
|
columns[i].col_property = prop;
|
||||||
|
columns[i].col_title = fx_property_get_name(prop);
|
||||||
|
columns[i].col_title_ptr = columns[i].col_title;
|
||||||
|
|
||||||
|
columns[i].col_width = tty_width / column_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_print_headers(struct table_format_ctx *ctx)
|
||||||
|
{
|
||||||
|
fx_printf("[bold,bright_green]");
|
||||||
|
bool repeat = false;
|
||||||
|
struct table_format_ctx_column *c = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
repeat = false;
|
||||||
|
for (size_t i = 0; i < ctx->ctx_columns_count; i++) {
|
||||||
|
c = &ctx->ctx_columns[i];
|
||||||
|
if (c->col_width == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t title_chars_remaining = strlen(c->col_title_ptr);
|
||||||
|
size_t to_write = title_chars_remaining;
|
||||||
|
if (to_write > c->col_width) {
|
||||||
|
to_write = c->col_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t x;
|
||||||
|
for (x = 0; x < to_write; x++) {
|
||||||
|
fx_stream_write_char(
|
||||||
|
ctx->ctx_out,
|
||||||
|
*c->col_title_ptr);
|
||||||
|
c->col_title_ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; x < c->col_width; x++) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_write != title_chars_remaining) {
|
||||||
|
repeat = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (repeat);
|
||||||
|
|
||||||
|
fx_stream_write_char(ctx->ctx_out, '\n');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ctx->ctx_columns_count; i++) {
|
||||||
|
struct table_format_ctx_column *c = &ctx->ctx_columns[i];
|
||||||
|
if (c->col_width == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t title_len = strlen(c->col_title);
|
||||||
|
if (title_len > c->col_width) {
|
||||||
|
title_len = c->col_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t x;
|
||||||
|
for (x = 0; x < title_len; x++) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; x < c->col_width; x++) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_printf("[reset]");
|
||||||
|
fx_stream_write_char(ctx->ctx_out, '\n');
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status table_format_ctx_print_record(
|
||||||
|
struct table_format_ctx *ctx,
|
||||||
|
const fx_value *record)
|
||||||
|
{
|
||||||
|
fx_stringstream *strm = fx_stringstream_create();
|
||||||
|
for (size_t i = 0; i < ctx->ctx_columns_count; i++) {
|
||||||
|
struct table_format_ctx_column *c = &ctx->ctx_columns[i];
|
||||||
|
if (c->col_width == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stringstream_reset(strm);
|
||||||
|
fx_value column_value = FX_VALUE_EMPTY;
|
||||||
|
if (c->col_property) {
|
||||||
|
fx_status status = fx_property_get_value(
|
||||||
|
c->col_property,
|
||||||
|
record,
|
||||||
|
&column_value);
|
||||||
|
if (FX_OK(status)) {
|
||||||
|
fx_value_to_string(&column_value, strm, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t to_write = fx_stringstream_get_length(strm);
|
||||||
|
const char *s = fx_stringstream_ptr(strm);
|
||||||
|
bool overflow = false;
|
||||||
|
if (to_write > c->col_width) {
|
||||||
|
to_write = c->col_width - 2;
|
||||||
|
overflow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t x;
|
||||||
|
for (x = 0; x < to_write; x++) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, s[x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, L'…');
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; x < c->col_width; x++) {
|
||||||
|
fx_stream_write_char(ctx->ctx_out, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stream_write_char(ctx->ctx_out, '\n');
|
||||||
|
fx_stringstream_unref(strm);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
static struct table_format_column verb_table_columns[] = {
|
||||||
|
TABLE_COLUMN("verb", "verb", 13),
|
||||||
|
TABLE_COLUMN("alias_prefix", "alias_prefix", 13),
|
||||||
|
TABLE_COLUMN("group", "group", 13),
|
||||||
|
TABLE_COLUMN("description", "description", COL_WIDTH_INFINITE),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct table_format verb_table_format = {
|
||||||
|
.fmt_columns = verb_table_columns,
|
||||||
|
.fmt_column_count = sizeof verb_table_columns
|
||||||
|
/ sizeof verb_table_columns[0],
|
||||||
|
};
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
#include "line-ed.h"
|
#include "line-ed.h"
|
||||||
|
|
||||||
const char *line_start(struct line_ed *ed, size_t y)
|
#include <fx/wstr.h>
|
||||||
|
|
||||||
|
const fx_wchar *line_start(struct line_ed *ed, size_t y)
|
||||||
{
|
{
|
||||||
const char *line = ed->l_buf;
|
const fx_wchar *line = ed->l_buf;
|
||||||
|
|
||||||
for (size_t i = 0; i < y; i++) {
|
for (size_t i = 0; i < y; i++) {
|
||||||
line += strcspn(line, "\n");
|
line += fx_wstrcspn(line, L"\n");
|
||||||
|
|
||||||
if (*line == '\n') {
|
if (*line == '\n') {
|
||||||
line++;
|
line++;
|
||||||
@@ -18,10 +21,10 @@ const char *line_start(struct line_ed *ed, size_t y)
|
|||||||
|
|
||||||
size_t line_length(struct line_ed *ed, size_t y)
|
size_t line_length(struct line_ed *ed, size_t y)
|
||||||
{
|
{
|
||||||
const char *line = ed->l_buf;
|
const fx_wchar *line = ed->l_buf;
|
||||||
|
|
||||||
for (size_t i = 0; i < y; i++) {
|
for (size_t i = 0; i < y; i++) {
|
||||||
line += strcspn(line, "\n");
|
line += fx_wstrcspn(line, L"\n");
|
||||||
if (*line == '\n') {
|
if (*line == '\n') {
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
@@ -31,7 +34,7 @@ size_t line_length(struct line_ed *ed, size_t y)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = strcspn(line, "\n");
|
size_t len = fx_wstrcspn(line, L"\n");
|
||||||
if (line[len] == '\n') {
|
if (line[len] == '\n') {
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
#ifndef LINE_ED_BUFFER_H_
|
#ifndef LINE_ED_BUFFER_H_
|
||||||
#define LINE_ED_BUFFER_H_
|
#define LINE_ED_BUFFER_H_
|
||||||
|
|
||||||
|
#include <fx/encoding.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct line_ed;
|
struct line_ed;
|
||||||
|
|
||||||
/* returns a pointer to the start of the line based on the given `y`
|
/* returns a pointer to the start of the line based on the given `y`
|
||||||
* coordinate */
|
* coordinate */
|
||||||
extern const char *line_start(struct line_ed *ed, size_t y);
|
extern const fx_wchar *line_start(struct line_ed *ed, size_t y);
|
||||||
/* returns the length of the line based on the given `y` coordinate.
|
/* returns the length of the line based on the given `y` coordinate.
|
||||||
* for any line other than the last line in the buffer, this length
|
* for any line other than the last line in the buffer, this length
|
||||||
* INCLUDES the trailing linefeed. */
|
* INCLUDES the trailing linefeed. */
|
||||||
|
|||||||
+33
-18
@@ -6,42 +6,55 @@
|
|||||||
|
|
||||||
void alloc_empty_history_entry(struct line_ed *ed)
|
void alloc_empty_history_entry(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
fx_string *str = (fx_string *)fx_array_at(
|
fx_value *str_v = fx_array_get_ref(
|
||||||
ed->l_history,
|
ed->l_history,
|
||||||
fx_array_size(ed->l_history) - 1);
|
fx_array_get_size(ed->l_history) - 1);
|
||||||
|
fx_string *str = NULL;
|
||||||
|
fx_value_get_object(str_v, &str);
|
||||||
if (!str || fx_string_get_size(str, FX_STRLEN_NORMAL) > 0) {
|
if (!str || fx_string_get_size(str, FX_STRLEN_NORMAL) > 0) {
|
||||||
str = fx_string_create();
|
str = fx_string_create();
|
||||||
fx_array_append(ed->l_history, (fx_object *)str);
|
fx_array_push_back(ed->l_history, FX_VALUE_OBJECT(str));
|
||||||
|
fx_string_unref(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
ed->l_history_pos = fx_array_size(ed->l_history) - 1;
|
ed->l_history_pos = fx_array_get_size(ed->l_history) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_buf_to_history(struct line_ed *ed)
|
void save_buf_to_history(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
fx_string *cur
|
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
|
||||||
= (fx_string *)fx_array_get(ed->l_history, ed->l_history_pos);
|
fx_string *cur = NULL;
|
||||||
fx_string_replace_all(cur, ed->l_buf);
|
fx_value_get_object(cur_v, &cur);
|
||||||
|
fx_string_clear(cur);
|
||||||
|
fx_string_append_wstr(cur, ed->l_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void append_buf_to_history(struct line_ed *ed)
|
void append_buf_to_history(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
fx_string *cur
|
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
|
||||||
= (fx_string *)fx_array_get(ed->l_history, ed->l_history_pos);
|
fx_string *cur = NULL;
|
||||||
|
fx_value_get_object(cur_v, &cur);
|
||||||
char s[] = {'\n', 0};
|
char s[] = {'\n', 0};
|
||||||
fx_string_append_cstr(cur, s);
|
fx_string_append_cstr(cur, s);
|
||||||
fx_string_append_cstr(cur, ed->l_buf);
|
fx_string_append_wstr(cur, ed->l_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_buf_from_history(struct line_ed *ed)
|
void load_buf_from_history(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
fx_string *cur
|
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
|
||||||
= (fx_string *)fx_array_at(ed->l_history, ed->l_history_pos);
|
fx_string *cur = NULL;
|
||||||
size_t len
|
fx_value_get_object(cur_v, &cur);
|
||||||
= MIN((size_t)(ed->l_buf_end - ed->l_buf - 1),
|
size_t len = MIN(
|
||||||
fx_string_get_size(cur, FX_STRLEN_NORMAL));
|
(size_t)(ed->l_buf_end - ed->l_buf - 1),
|
||||||
|
fx_string_get_size(cur, FX_STRLEN_CODEPOINTS));
|
||||||
|
|
||||||
|
const char *src = fx_string_get_cstr(cur);
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
fx_wchar ch_src = fx_wchar_utf8_codepoint_decode(src);
|
||||||
|
ed->l_buf[i] = ch_src;
|
||||||
|
src += fx_wchar_utf8_codepoint_stride(src);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(ed->l_buf, fx_string_get_cstr(cur), len);
|
|
||||||
ed->l_buf[len] = '\0';
|
ed->l_buf[len] = '\0';
|
||||||
|
|
||||||
unsigned int x = 0, y = 0;
|
unsigned int x = 0, y = 0;
|
||||||
@@ -62,11 +75,13 @@ void load_buf_from_history(struct line_ed *ed)
|
|||||||
|
|
||||||
const char *last_history_line(struct line_ed *ed)
|
const char *last_history_line(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
size_t nlines = fx_array_size(ed->l_history);
|
size_t nlines = fx_array_get_size(ed->l_history);
|
||||||
if (nlines < 2) {
|
if (nlines < 2) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_string *last = (fx_string *)fx_array_at(ed->l_history, nlines - 2);
|
fx_value *last_v = fx_array_get_ref(ed->l_history, nlines - 2);
|
||||||
|
fx_string *last = NULL;
|
||||||
|
fx_value_get_object(last_v, &last);
|
||||||
return fx_string_get_cstr(last);
|
return fx_string_get_cstr(last);
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-22
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void put_char(struct line_ed *ed, char c)
|
void put_char(struct line_ed *ed, fx_wchar c)
|
||||||
{
|
{
|
||||||
if (ed->l_buf_ptr > ed->l_line_end + 1) {
|
if (ed->l_buf_ptr > ed->l_line_end + 1) {
|
||||||
return;
|
return;
|
||||||
@@ -21,8 +21,8 @@ void put_char(struct line_ed *ed, char c)
|
|||||||
|
|
||||||
size_t prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
size_t prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
||||||
|
|
||||||
char *dest = ed->l_buf_ptr;
|
fx_wchar *dest = ed->l_buf_ptr;
|
||||||
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
|
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
|
||||||
|
|
||||||
if (dest < ed->l_line_end) {
|
if (dest < ed->l_line_end) {
|
||||||
memmove(dest + 1, dest, len);
|
memmove(dest + 1, dest, len);
|
||||||
@@ -55,8 +55,8 @@ static void backspace_simple(struct line_ed *ed)
|
|||||||
|
|
||||||
size_t prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
size_t prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
||||||
|
|
||||||
char *dest = ed->l_buf_ptr;
|
fx_wchar *dest = ed->l_buf_ptr;
|
||||||
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
|
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
|
||||||
memmove(dest - 1, dest, len);
|
memmove(dest - 1, dest, len);
|
||||||
|
|
||||||
ed->l_cursor_x--;
|
ed->l_cursor_x--;
|
||||||
@@ -78,8 +78,8 @@ static void backspace_nl(struct line_ed *ed)
|
|||||||
.r_prev_line_len = prev_line_len,
|
.r_prev_line_len = prev_line_len,
|
||||||
};
|
};
|
||||||
|
|
||||||
char *dest = ed->l_buf_ptr;
|
fx_wchar *dest = ed->l_buf_ptr;
|
||||||
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
|
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
|
||||||
memmove(dest - 1, dest, len);
|
memmove(dest - 1, dest, len);
|
||||||
|
|
||||||
ed->l_cursor_x = prev_line_len - 1;
|
ed->l_cursor_x = prev_line_len - 1;
|
||||||
@@ -112,7 +112,7 @@ void backspace(struct line_ed *ed)
|
|||||||
void cursor_left(struct line_ed *ed)
|
void cursor_left(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
if (ed->l_cursor_x != 0) {
|
if (ed->l_cursor_x != 0) {
|
||||||
//fputs("\010", stdout);
|
// fputs("\010", stdout);
|
||||||
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_CURSOR, -1);
|
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_CURSOR, -1);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
ed->l_cursor_x--;
|
ed->l_cursor_x--;
|
||||||
@@ -120,7 +120,8 @@ void cursor_left(struct line_ed *ed)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ed->l_cursor_y <= ed->l_continuations || ed->l_buf_ptr <= ed->l_buf) {
|
if (ed->l_cursor_y <= ed->l_continuations
|
||||||
|
|| ed->l_buf_ptr <= ed->l_buf) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +135,12 @@ void cursor_left(struct line_ed *ed)
|
|||||||
size_t len = line_length(ed, ed->l_cursor_y);
|
size_t len = line_length(ed, ed->l_cursor_y);
|
||||||
ed->l_cursor_x = len - 1;
|
ed->l_cursor_x = len - 1;
|
||||||
|
|
||||||
//printf("\033[A\033[%dG", len + prompt_len);
|
// printf("\033[A\033[%dG", len + prompt_len);
|
||||||
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, -1);
|
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, -1);
|
||||||
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_START, (int)(len + prompt_len));
|
fx_tty_move_cursor_x(
|
||||||
|
ed->l_tty,
|
||||||
|
FX_TTY_POS_START,
|
||||||
|
(int)(len + prompt_len));
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
@@ -150,7 +154,7 @@ void cursor_right(struct line_ed *ed)
|
|||||||
if (*ed->l_buf_ptr != '\n') {
|
if (*ed->l_buf_ptr != '\n') {
|
||||||
ed->l_cursor_x++;
|
ed->l_cursor_x++;
|
||||||
ed->l_buf_ptr++;
|
ed->l_buf_ptr++;
|
||||||
//fputs("\033[C", stdout);
|
// fputs("\033[C", stdout);
|
||||||
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_CURSOR, 1);
|
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_CURSOR, 1);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return;
|
return;
|
||||||
@@ -164,7 +168,7 @@ void cursor_right(struct line_ed *ed)
|
|||||||
ed->l_cursor_x = 0;
|
ed->l_cursor_x = 0;
|
||||||
ed->l_buf_ptr++;
|
ed->l_buf_ptr++;
|
||||||
|
|
||||||
//printf("\033[B\033[G");
|
// printf("\033[B\033[G");
|
||||||
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, 1);
|
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, 1);
|
||||||
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_START, 0);
|
fx_tty_move_cursor_x(ed->l_tty, FX_TTY_POS_START, 0);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -177,13 +181,18 @@ void arrow_up(struct line_ed *ed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ed->l_cursor_y > 0) {
|
if (ed->l_cursor_y > 0) {
|
||||||
//printf("\033[%uA", ed->l_cursor_y);
|
// printf("\033[%uA", ed->l_cursor_y);
|
||||||
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, (long long)ed->l_cursor_y);
|
fx_tty_move_cursor_y(
|
||||||
|
ed->l_tty,
|
||||||
|
FX_TTY_POS_CURSOR,
|
||||||
|
(long long)ed->l_cursor_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
// printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
||||||
fx_tty_move_cursor_x(
|
fx_tty_move_cursor_x(
|
||||||
ed->l_tty, FX_TTY_POS_START, (long long)prompt_length(ed, PROMPT_MAIN));
|
ed->l_tty,
|
||||||
|
FX_TTY_POS_START,
|
||||||
|
(long long)prompt_length(ed, PROMPT_MAIN));
|
||||||
fx_tty_clear(ed->l_tty, FX_TTY_CLEAR_SCREEN | FX_TTY_CLEAR_FROM_CURSOR);
|
fx_tty_clear(ed->l_tty, FX_TTY_CLEAR_SCREEN | FX_TTY_CLEAR_FROM_CURSOR);
|
||||||
|
|
||||||
save_buf_to_history(ed);
|
save_buf_to_history(ed);
|
||||||
@@ -196,18 +205,23 @@ void arrow_up(struct line_ed *ed)
|
|||||||
|
|
||||||
void arrow_down(struct line_ed *ed)
|
void arrow_down(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
if (ed->l_history_pos == fx_array_size(ed->l_history) - 1) {
|
if (ed->l_history_pos == fx_array_get_size(ed->l_history) - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ed->l_cursor_y > 0) {
|
if (ed->l_cursor_y > 0) {
|
||||||
//printf("\033[%uA", ed->l_cursor_y);
|
// printf("\033[%uA", ed->l_cursor_y);
|
||||||
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, (int)ed->l_cursor_y);
|
fx_tty_move_cursor_y(
|
||||||
|
ed->l_tty,
|
||||||
|
FX_TTY_POS_CURSOR,
|
||||||
|
(int)ed->l_cursor_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
// printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
||||||
fx_tty_move_cursor_x(
|
fx_tty_move_cursor_x(
|
||||||
ed->l_tty, FX_TTY_POS_START, prompt_length(ed, PROMPT_MAIN) + 1);
|
ed->l_tty,
|
||||||
|
FX_TTY_POS_START,
|
||||||
|
prompt_length(ed, PROMPT_MAIN) + 1);
|
||||||
|
|
||||||
save_buf_to_history(ed);
|
save_buf_to_history(ed);
|
||||||
ed->l_history_pos++;
|
ed->l_history_pos++;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#ifndef LINE_ED_INPUT_H_
|
#ifndef LINE_ED_INPUT_H_
|
||||||
#define LINE_ED_INPUT_H_
|
#define LINE_ED_INPUT_H_
|
||||||
|
|
||||||
|
#include <fx/encoding.h>
|
||||||
|
|
||||||
struct line_ed;
|
struct line_ed;
|
||||||
|
|
||||||
extern void put_char(struct line_ed *ed, char c);
|
extern void put_char(struct line_ed *ed, fx_wchar c);
|
||||||
extern void backspace(struct line_ed *ed);
|
extern void backspace(struct line_ed *ed);
|
||||||
extern void cursor_left(struct line_ed *ed);
|
extern void cursor_left(struct line_ed *ed);
|
||||||
extern void cursor_right(struct line_ed *ed);
|
extern void cursor_right(struct line_ed *ed);
|
||||||
|
|||||||
+16
-15
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fx/term/tty.h>
|
#include <fx/term/tty.h>
|
||||||
|
#include <fx/wstr.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -98,13 +99,13 @@ static void clear_buffer(struct line_ed *ed)
|
|||||||
ed->l_continuations = 0;
|
ed->l_continuations = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convert_continuation_feeds(char *s, size_t max)
|
static void convert_continuation_feeds(fx_wchar *s, size_t max)
|
||||||
{
|
{
|
||||||
char *end = s + max;
|
fx_wchar *end = s + max;
|
||||||
size_t len = strlen(s);
|
size_t len = fx_wstrlen(s);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t r = strcspn(s, "\\");
|
size_t r = fx_wstrcspn(s, L"\\");
|
||||||
if (s + r > end) {
|
if (s + r > end) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -126,13 +127,13 @@ static void convert_continuation_feeds(char *s, size_t max)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_continuation_feeds(char *s, size_t max)
|
static void remove_continuation_feeds(fx_wchar *s, size_t max)
|
||||||
{
|
{
|
||||||
char *end = s + max;
|
fx_wchar *end = s + max;
|
||||||
size_t len = strlen(s);
|
size_t len = fx_wstrlen(s);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t r = strcspn(s, "\\");
|
size_t r = fx_wstrcspn(s, L"\\");
|
||||||
if (s + r > end) {
|
if (s + r > end) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -156,9 +157,9 @@ static void remove_continuation_feeds(char *s, size_t max)
|
|||||||
|
|
||||||
static bool input_is_empty(struct line_ed *ed)
|
static bool input_is_empty(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
const char *p = ed->l_buf;
|
const fx_wchar *p = ed->l_buf;
|
||||||
while (p < ed->l_line_end) {
|
while (p < ed->l_line_end) {
|
||||||
if (!isspace(*p)) {
|
if (!fx_wchar_is_space(*p)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +189,7 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
|
|||||||
fputc('\r', stdout);
|
fputc('\r', stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fputc(ed->l_buf[i], stdout);
|
fx_stream_write_char(fx_stdout, ed->l_buf[i]);
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
|
|||||||
arrow_down(ed);
|
arrow_down(ed);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (iswgraph(key) || key == ' ') {
|
if (fx_wchar_is_graph(key) || key == ' ') {
|
||||||
put_char(ed, key);
|
put_char(ed, key);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -275,10 +276,10 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
|
|||||||
ed->l_history_pos = append_to_index;
|
ed->l_history_pos = append_to_index;
|
||||||
append_buf_to_history(ed);
|
append_buf_to_history(ed);
|
||||||
} else {
|
} else {
|
||||||
ed->l_history_pos = fx_array_size(ed->l_history) - 1;
|
ed->l_history_pos = fx_array_get_size(ed->l_history) - 1;
|
||||||
|
|
||||||
const char *last = last_history_line(ed);
|
const char *last = last_history_line(ed);
|
||||||
if (!last || strcmp(last, ed->l_buf) != 0) {
|
if (!last || fx_wastrcmp(last, ed->l_buf) != 0) {
|
||||||
save_buf_to_history(ed);
|
save_buf_to_history(ed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +295,7 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
|
|||||||
convert_continuation_feeds(ed->l_buf, sz);
|
convert_continuation_feeds(ed->l_buf, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_stream_write_cstr(out, ed->l_buf, NULL);
|
fx_stream_write_wstr(out, ed->l_buf, NULL);
|
||||||
fx_stream_write_char(out, '\n');
|
fx_stream_write_char(out, '\n');
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ struct line_ed {
|
|||||||
/* input buffer, pointer to the buffer cell that corresponds to
|
/* input buffer, pointer to the buffer cell that corresponds to
|
||||||
* the current cursor position, and pointer to the byte AFTER the last
|
* the current cursor position, and pointer to the byte AFTER the last
|
||||||
* usable byte in the buffer */
|
* usable byte in the buffer */
|
||||||
char *l_buf, *l_buf_ptr, *l_buf_end;
|
fx_wchar *l_buf, *l_buf_ptr, *l_buf_end;
|
||||||
/* pointer to the byte AFTER the last byte of the user's input */
|
/* pointer to the byte AFTER the last byte of the user's input */
|
||||||
char *l_line_end;
|
fx_wchar *l_line_end;
|
||||||
/* 2-dimensional coordinates of the current cursor position.
|
/* 2-dimensional coordinates of the current cursor position.
|
||||||
* this does NOT include any prompts that are visible on the terminal */
|
* this does NOT include any prompts that are visible on the terminal */
|
||||||
size_t l_cursor_x, l_cursor_y;
|
size_t l_cursor_x, l_cursor_y;
|
||||||
|
|||||||
+13
-12
@@ -5,6 +5,7 @@
|
|||||||
#include "line-ed.h"
|
#include "line-ed.h"
|
||||||
|
|
||||||
#include <fx/term/tty.h>
|
#include <fx/term/tty.h>
|
||||||
|
#include <fx/wstr.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -15,19 +16,19 @@
|
|||||||
* the (x, y) coordinates provided should be the data coordinates of the
|
* the (x, y) coordinates provided should be the data coordinates of the
|
||||||
* first character in `s`.
|
* first character in `s`.
|
||||||
*/
|
*/
|
||||||
void print_text(struct line_ed *ed, size_t x, size_t y, const char *s)
|
void print_text(struct line_ed *ed, size_t x, size_t y, const fx_wchar *s)
|
||||||
{
|
{
|
||||||
fx_tty *tty = ed->l_tty;
|
fx_tty *tty = ed->l_tty;
|
||||||
|
|
||||||
for (size_t i = 0; s[i] != '\n' && s[i] != '\0'; i++) {
|
for (size_t i = 0; s[i] != '\n' && s[i] != '\0'; i++) {
|
||||||
fputc(s[i], stdout);
|
fx_stream_write_char(fx_stdout, s[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_buffer(struct line_ed *ed)
|
void print_buffer(struct line_ed *ed)
|
||||||
{
|
{
|
||||||
const char *line_buf = ed->l_buf;
|
const fx_wchar *line_buf = ed->l_buf;
|
||||||
size_t line_len = strcspn(line_buf, "\n");
|
size_t line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
|
|
||||||
unsigned int y = 0;
|
unsigned int y = 0;
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ void print_buffer(struct line_ed *ed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
y++;
|
y++;
|
||||||
line_len = strcspn(line_buf, "\n");
|
line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
|
|
||||||
fputc('\r', stdout);
|
fputc('\r', stdout);
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
@@ -74,8 +75,8 @@ void print_buffer(struct line_ed *ed)
|
|||||||
void put_refresh(struct line_ed *ed, struct refresh_state *state)
|
void put_refresh(struct line_ed *ed, struct refresh_state *state)
|
||||||
{
|
{
|
||||||
/* get the data for the line that is being refreshed */
|
/* get the data for the line that is being refreshed */
|
||||||
const char *line_buf = line_start(ed, ed->l_cursor_y);
|
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
|
||||||
size_t line_len = strcspn(line_buf, "\n");
|
size_t line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
|
|
||||||
/* the index of the first char in line_buf that needs to be reprinted */
|
/* the index of the first char in line_buf that needs to be reprinted */
|
||||||
size_t start_x = state->r_prev_cursor_x;
|
size_t start_x = state->r_prev_cursor_x;
|
||||||
@@ -128,8 +129,8 @@ void backspace_nl_refresh(struct line_ed *ed, struct refresh_state *state)
|
|||||||
/* get the data for the line that is being refreshed.
|
/* get the data for the line that is being refreshed.
|
||||||
* relative to where the cursor was before the linefeed was deleted,
|
* relative to where the cursor was before the linefeed was deleted,
|
||||||
* this is the PREVIOUS line. */
|
* this is the PREVIOUS line. */
|
||||||
const char *line_buf = line_start(ed, ed->l_cursor_y);
|
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
|
||||||
size_t line_len = strcspn(line_buf, "\n");
|
size_t line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
|
|
||||||
/* the index of the first char in line_buf that needs to be reprinted.
|
/* the index of the first char in line_buf that needs to be reprinted.
|
||||||
* subtract one to account for the linefeed that has since been deleted.
|
* subtract one to account for the linefeed that has since been deleted.
|
||||||
@@ -188,7 +189,7 @@ void backspace_nl_refresh(struct line_ed *ed, struct refresh_state *state)
|
|||||||
line_buf + start_x);
|
line_buf + start_x);
|
||||||
|
|
||||||
line_buf += line_len + 1;
|
line_buf += line_len + 1;
|
||||||
line_len = strcspn(line_buf, "\n");
|
line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
start_x = 0;
|
start_x = 0;
|
||||||
|
|
||||||
if (*line_buf == '\0') {
|
if (*line_buf == '\0') {
|
||||||
@@ -218,8 +219,8 @@ void backspace_nl_refresh(struct line_ed *ed, struct refresh_state *state)
|
|||||||
void backspace_simple_refresh(struct line_ed *ed, struct refresh_state *state)
|
void backspace_simple_refresh(struct line_ed *ed, struct refresh_state *state)
|
||||||
{
|
{
|
||||||
/* get the data for the line that is being refreshed */
|
/* get the data for the line that is being refreshed */
|
||||||
const char *line_buf = line_start(ed, ed->l_cursor_y);
|
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
|
||||||
size_t line_len = strcspn(line_buf, "\n");
|
size_t line_len = fx_wstrcspn(line_buf, L"\n");
|
||||||
|
|
||||||
/* the index of the first char in line_buf that needs to be reprinted */
|
/* the index of the first char in line_buf that needs to be reprinted */
|
||||||
size_t start_x = ed->l_cursor_x;
|
size_t start_x = ed->l_cursor_x;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef LINE_ED_REFRESH_H_
|
#ifndef LINE_ED_REFRESH_H_
|
||||||
#define LINE_ED_REFRESH_H_
|
#define LINE_ED_REFRESH_H_
|
||||||
|
|
||||||
|
#include <fx/encoding.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct line_ed;
|
struct line_ed;
|
||||||
@@ -15,7 +16,11 @@ struct refresh_state {
|
|||||||
size_t r_prev_line_len;
|
size_t r_prev_line_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void print_text(struct line_ed *ed, size_t x, size_t y, const char *s);
|
extern void print_text(
|
||||||
|
struct line_ed *ed,
|
||||||
|
size_t x,
|
||||||
|
size_t y,
|
||||||
|
const fx_wchar *s);
|
||||||
extern void print_buffer(struct line_ed *ed);
|
extern void print_buffer(struct line_ed *ed);
|
||||||
extern void put_refresh(struct line_ed *ed, struct refresh_state *state);
|
extern void put_refresh(struct line_ed *ed, struct refresh_state *state);
|
||||||
extern void backspace_nl_refresh(
|
extern void backspace_nl_refresh(
|
||||||
|
|||||||
+89
-9
@@ -1,37 +1,117 @@
|
|||||||
|
#include "ast/ast.h"
|
||||||
|
#include "compile.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "format/format.h"
|
||||||
#include "line-ed/line-ed.h"
|
#include "line-ed/line-ed.h"
|
||||||
|
#include "parse/lex.h"
|
||||||
|
#include "parse/parse.h"
|
||||||
|
#include "parse/token.h"
|
||||||
|
#include "runtime/runtime.h"
|
||||||
|
#include "verb.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static void print_token_queue(fx_queue *q)
|
||||||
|
{
|
||||||
|
fx_queue_entry *cur = fx_queue_first(q);
|
||||||
|
while (cur) {
|
||||||
|
struct lex_token *tok = fx_unbox(
|
||||||
|
struct lex_token,
|
||||||
|
cur,
|
||||||
|
tok_entry);
|
||||||
|
print_lex_token(tok);
|
||||||
|
cur = fx_queue_next(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lex_only(struct lex_ctx *lex)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
struct lex_token *tok = lex_ctx_peek(lex);
|
||||||
|
if (!tok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lex_ctx_discard(lex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lex_and_parse(struct parse_ctx *parse)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int compare_token_types(unsigned int a, unsigned int b);
|
||||||
|
|
||||||
int main(int argc, const char **argv)
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
printf("B Shell " BSHELL_VERSION "\n");
|
printf("B Shell " BSHELL_VERSION "\n");
|
||||||
|
|
||||||
|
bshell_init_all_verbs();
|
||||||
|
table_format_init();
|
||||||
|
|
||||||
|
struct file *file = NULL;
|
||||||
|
struct line_ed *ed = NULL;
|
||||||
struct line_source *linesrc = NULL;
|
struct line_source *linesrc = NULL;
|
||||||
|
|
||||||
enum bshell_status status = BSHELL_SUCCESS;
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
struct file *file = NULL;
|
|
||||||
status = file_open(argv[1], &file);
|
status = file_open(argv[1], &file);
|
||||||
linesrc = &file->f_base;
|
linesrc = &file->f_base;
|
||||||
} else {
|
} else {
|
||||||
struct line_ed *ed = line_ed_create();
|
#if BSHELL_INTERACTIVE == 1
|
||||||
|
ed = line_ed_create();
|
||||||
linesrc = line_ed_to_line_source(ed);
|
linesrc = line_ed_to_line_source(ed);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "Interactive mode is not supported.\n");
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_stringstream *linebuf = fx_stringstream_create();
|
struct lex_ctx lex = {0};
|
||||||
|
lex_ctx_init(&lex, LEX_PRINT_TOKENS, linesrc);
|
||||||
|
struct parse_ctx parse = {0};
|
||||||
|
parse_ctx_init(&parse, &lex);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
lex_only(&lex);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bshell_scriptblock *block = bshell_scriptblock_create();
|
||||||
|
struct bshell_runtime *rt = bshell_runtime_create();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
enum bshell_status status
|
struct ast_node *node = parse_ctx_read_node(&parse);
|
||||||
= line_source_readline(linesrc, linebuf);
|
if (!node) {
|
||||||
|
|
||||||
if (status != BSHELL_SUCCESS) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s", fx_stringstream_ptr(linebuf));
|
print_ast_node_recursive(node);
|
||||||
fx_stringstream_reset(linebuf);
|
printf("----\n");
|
||||||
|
|
||||||
|
bshell_scriptblock_clear_text(block);
|
||||||
|
bshell_compile(node, block);
|
||||||
|
print_scriptblock(block, 0);
|
||||||
|
|
||||||
|
fx_value result = bshell_runtime_eval_global(rt, block);
|
||||||
|
if (result.v_type != NULL) {
|
||||||
|
format_value_default(&result, fx_stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_ctx_cleanup(&parse);
|
||||||
|
lex_ctx_cleanup(&lex);
|
||||||
|
|
||||||
|
#if BSHELL_INTERACTIVE == 1
|
||||||
|
if (ed) {
|
||||||
|
line_ed_destroy(ed);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
file_close(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+14
-10
@@ -18,10 +18,6 @@
|
|||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
static const struct operator_info operators[] = {
|
static const struct operator_info operators[] = {
|
||||||
OP(SUBEXPR, PARENTHESIS, LEFT, PREFIX, UNARY),
|
|
||||||
OP(ARRAY_START, PARENTHESIS, LEFT, PREFIX, UNARY),
|
|
||||||
OP(PAREN, PARENTHESIS, LEFT, PREFIX, UNARY),
|
|
||||||
OP(HASHTABLE_START, PARENTHESIS, LEFT, PREFIX, UNARY),
|
|
||||||
OP(ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
|
OP(ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
|
||||||
OP(CONDITIONAL_ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
|
OP(CONDITIONAL_ACCESS, MEMBER_ACCESS, LEFT, INFIX, BINARY),
|
||||||
OP(STATIC_ACCESS, STATIC_ACCESS, LEFT, INFIX, BINARY),
|
OP(STATIC_ACCESS, STATIC_ACCESS, LEFT, INFIX, BINARY),
|
||||||
@@ -73,12 +69,20 @@ static const struct operator_info operators[] = {
|
|||||||
OP(LEFT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
|
OP(LEFT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
|
||||||
OP(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
|
OP(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
|
||||||
|
|
||||||
OP(ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
OP(ADD_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(ADD_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
OP(SUBTRACT_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(SUBTRACT_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
OP(MULTIPLY_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(MULTIPLY_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
OP(DIVIDE_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(DIVIDE_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
OP(MODULO_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
|
OP(MODULO_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
|
||||||
|
|
||||||
|
/* these are not real operators, and are just used internally by the
|
||||||
|
* parser. */
|
||||||
|
OP(SUBEXPR, PARENTHESIS, LEFT, PREFIX, UNARY),
|
||||||
|
OP(ARRAY_START, PARENTHESIS, LEFT, PREFIX, UNARY),
|
||||||
|
OP(PAREN, PARENTHESIS, LEFT, PREFIX, UNARY),
|
||||||
|
OP(HASHTABLE_START, PARENTHESIS, LEFT, PREFIX, UNARY),
|
||||||
|
OP(SCRIPTBLOCK, PARENTHESIS, LEFT, PREFIX, UNARY),
|
||||||
};
|
};
|
||||||
static const size_t nr_operators = sizeof operators / sizeof operators[0];
|
static const size_t nr_operators = sizeof operators / sizeof operators[0];
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ enum operator_id {
|
|||||||
OP_CAST,
|
OP_CAST,
|
||||||
OP_SUBEXPR,
|
OP_SUBEXPR,
|
||||||
OP_PAREN,
|
OP_PAREN,
|
||||||
|
OP_SCRIPTBLOCK,
|
||||||
OP_ARRAY_START,
|
OP_ARRAY_START,
|
||||||
OP_HASHTABLE_START,
|
OP_HASHTABLE_START,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,18 +19,19 @@ static enum bshell_status arithmetic_hyphen(struct lex_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int token_type = TOK_WORD;
|
unsigned int token_type = TOK_WORD;
|
||||||
if (convert_word_to_int(tok)) {
|
if (convert_word_to_number(tok)) {
|
||||||
token_type = TOK_INT;
|
token_type = tok->tok_type;
|
||||||
|
|
||||||
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
||||||
* tokens are detected properly), the resulting number will be
|
* tokens are detected properly), the resulting number will be
|
||||||
* negative.
|
* negative.
|
||||||
* this token will be preceded by a HYPHEN token, so the number
|
* this token will be preceded by a HYPHEN token, so the number
|
||||||
* must be positive */
|
* must be positive */
|
||||||
tok->tok_int *= -1;
|
fx_value neg = FX_INT(-1);
|
||||||
|
fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number);
|
||||||
push_symbol(ctx, SYM_HYPHEN);
|
push_symbol(ctx, SYM_HYPHEN);
|
||||||
} else if (convert_word_to_operator(ctx, tok)) {
|
} else if (convert_word_to_operator(ctx, tok)) {
|
||||||
token_type = TOK_OPERATOR;
|
token_type = tok->tok_operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueue_token(ctx, tok);
|
enqueue_token(ctx, tok);
|
||||||
@@ -108,8 +109,8 @@ static enum bshell_status arithmetic_word(struct lex_ctx *ctx)
|
|||||||
bool kw = false, number = false;
|
bool kw = false, number = false;
|
||||||
if (convert_word_to_keyword(word)) {
|
if (convert_word_to_keyword(word)) {
|
||||||
token_type = word->tok_keyword;
|
token_type = word->tok_keyword;
|
||||||
} else if (convert_word_to_int(word)) {
|
} else if (convert_word_to_number(word)) {
|
||||||
token_type = TOK_INT;
|
token_type = word->tok_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_lex_state_transition(ctx, token_type);
|
handle_lex_state_transition(ctx, token_type);
|
||||||
@@ -149,7 +150,6 @@ static enum bshell_status arithmetic_pump_token(struct lex_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct lex_state_link links[] = {
|
static const struct lex_state_link links[] = {
|
||||||
LINK_CHANGE(TOK_WORD, LEX_STATE_COMMAND),
|
|
||||||
LINK_CHANGE(SYM_EQUAL, LEX_STATE_STATEMENT),
|
LINK_CHANGE(SYM_EQUAL, LEX_STATE_STATEMENT),
|
||||||
LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0),
|
LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0),
|
||||||
LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0),
|
LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0),
|
||||||
|
|||||||
@@ -19,14 +19,15 @@ static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int token_type = TOK_WORD;
|
unsigned int token_type = TOK_WORD;
|
||||||
if (convert_word_to_int(tok)) {
|
if (convert_word_to_number(tok)) {
|
||||||
token_type = TOK_INT;
|
token_type = tok->tok_type;
|
||||||
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
||||||
* tokens are detected properly), the resulting number will be
|
* tokens are detected properly), the resulting number will be
|
||||||
* negative.
|
* negative.
|
||||||
* this token will be preceded by a HYPHEN token, so the number
|
* this token will be preceded by a HYPHEN token, so the number
|
||||||
* must be positive */
|
* must be positive */
|
||||||
tok->tok_int *= -1;
|
fx_value neg = FX_INT(-1);
|
||||||
|
fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number);
|
||||||
push_symbol(ctx, SYM_HYPHEN);
|
push_symbol(ctx, SYM_HYPHEN);
|
||||||
} else if (convert_word_to_operator(ctx, tok)) {
|
} else if (convert_word_to_operator(ctx, tok)) {
|
||||||
token_type = tok->tok_operator;
|
token_type = tok->tok_operator;
|
||||||
@@ -102,7 +103,7 @@ static enum bshell_status hashtable_word(struct lex_ctx *ctx)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_word_to_int(word);
|
convert_word_to_number(word);
|
||||||
|
|
||||||
handle_lex_state_transition(ctx, word->tok_type);
|
handle_lex_state_transition(ctx, word->tok_type);
|
||||||
enqueue_token(ctx, word);
|
enqueue_token(ctx, word);
|
||||||
|
|||||||
@@ -123,8 +123,11 @@ extern fx_wchar peek2_char_noread(struct lex_ctx *ctx);
|
|||||||
extern void advance_char(struct lex_ctx *ctx);
|
extern void advance_char(struct lex_ctx *ctx);
|
||||||
extern void advance_char_noread(struct lex_ctx *ctx);
|
extern void advance_char_noread(struct lex_ctx *ctx);
|
||||||
|
|
||||||
extern bool string_is_valid_number(const char *s, long long *out);
|
extern bool string_is_valid_number(
|
||||||
extern bool convert_word_to_int(struct lex_token *tok);
|
const char *s,
|
||||||
|
fx_value *out,
|
||||||
|
enum token_type *out_type);
|
||||||
|
extern bool convert_word_to_number(struct lex_token *tok);
|
||||||
extern bool convert_word_to_keyword(struct lex_token *tok);
|
extern bool convert_word_to_keyword(struct lex_token *tok);
|
||||||
extern bool convert_word_to_operator(
|
extern bool convert_word_to_operator(
|
||||||
struct lex_ctx *ctx,
|
struct lex_ctx *ctx,
|
||||||
|
|||||||
+93
-34
@@ -273,8 +273,10 @@ static struct lex_symbol_node *get_symbol_node(
|
|||||||
{
|
{
|
||||||
fx_queue_entry *entry = fx_queue_first(&node->s_children);
|
fx_queue_entry *entry = fx_queue_first(&node->s_children);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct lex_symbol_node *child
|
struct lex_symbol_node *child = fx_unbox(
|
||||||
= fx_unbox(struct lex_symbol_node, entry, s_entry);
|
struct lex_symbol_node,
|
||||||
|
entry,
|
||||||
|
s_entry);
|
||||||
if (child->s_char == c) {
|
if (child->s_char == c) {
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -319,8 +321,10 @@ static void destroy_symbol_tree(struct lex_symbol_node *tree)
|
|||||||
{
|
{
|
||||||
fx_queue_entry *entry = fx_queue_first(&tree->s_children);
|
fx_queue_entry *entry = fx_queue_first(&tree->s_children);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct lex_symbol_node *node
|
struct lex_symbol_node *node = fx_unbox(
|
||||||
= fx_unbox(struct lex_symbol_node, entry, s_entry);
|
struct lex_symbol_node,
|
||||||
|
entry,
|
||||||
|
s_entry);
|
||||||
fx_queue_entry *next = fx_queue_next(entry);
|
fx_queue_entry *next = fx_queue_next(entry);
|
||||||
fx_queue_delete(&tree->s_children, entry);
|
fx_queue_delete(&tree->s_children, entry);
|
||||||
|
|
||||||
@@ -595,44 +599,88 @@ static size_t get_int_multiplier_by_suffix(const char *suffix)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool string_is_valid_number(const char *s, long long *out)
|
static bool string_could_be_double(const char *s)
|
||||||
{
|
{
|
||||||
if (s[0] == '\0') {
|
if (strchr(s, '.')) {
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int base = get_int_base_by_prefix(&s);
|
|
||||||
|
|
||||||
char *ep = NULL;
|
|
||||||
long long value = strtoll(s, &ep, base);
|
|
||||||
if (*ep == '\0') {
|
|
||||||
out && (*out = value);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t multiplier = get_int_multiplier_by_suffix(ep);
|
if (strchr(s, 'e') || strchr(s, 'E')) {
|
||||||
if (multiplier != 0) {
|
|
||||||
out && (*out = value * multiplier);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool convert_word_to_int(struct lex_token *tok)
|
bool string_is_valid_number(
|
||||||
|
const char *s,
|
||||||
|
fx_value *out,
|
||||||
|
enum token_type *out_type)
|
||||||
|
{
|
||||||
|
if (s[0] == '\0') {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *ep = NULL;
|
||||||
|
double dvalue = strtod(s, &ep);
|
||||||
|
if (string_could_be_double(s) && *ep == '\0') {
|
||||||
|
if (out) {
|
||||||
|
*out = FX_DOUBLE(dvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_type) {
|
||||||
|
*out_type = TOK_DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base = get_int_base_by_prefix(&s);
|
||||||
|
|
||||||
|
long long ivalue = strtoll(s, &ep, base);
|
||||||
|
if (*ep == '\0') {
|
||||||
|
if (out) {
|
||||||
|
*out = FX_LONGLONG(ivalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_type) {
|
||||||
|
*out_type = TOK_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t multiplier = get_int_multiplier_by_suffix(ep);
|
||||||
|
if (multiplier != 0) {
|
||||||
|
if (out) {
|
||||||
|
*out = FX_LONGLONG(ivalue * multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_type) {
|
||||||
|
*out_type = TOK_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool convert_word_to_number(struct lex_token *tok)
|
||||||
{
|
{
|
||||||
if (!lex_token_has_string_value(tok)) {
|
if (!lex_token_has_string_value(tok)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *s = tok->tok_str;
|
const char *s = tok->tok_str;
|
||||||
long long value = 0;
|
fx_value value;
|
||||||
if (!string_is_valid_number(s, &value)) {
|
enum token_type type;
|
||||||
|
if (!string_is_valid_number(s, &value, &type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lex_token_change_type(tok, TOK_INT);
|
lex_token_change_type(tok, type);
|
||||||
tok->tok_int = value;
|
tok->tok_number = value;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -736,8 +784,9 @@ enum bshell_status read_var(
|
|||||||
return ctx->lex_status;
|
return ctx->lex_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lex_token *tok
|
struct lex_token *tok = lex_token_create_with_string(
|
||||||
= lex_token_create_with_string(type, fx_string_get_cstr(tmp));
|
type,
|
||||||
|
fx_string_get_cstr(tmp));
|
||||||
|
|
||||||
*out = tok;
|
*out = tok;
|
||||||
return BSHELL_SUCCESS;
|
return BSHELL_SUCCESS;
|
||||||
@@ -776,8 +825,9 @@ enum bshell_status read_braced_var(
|
|||||||
return ctx->lex_status;
|
return ctx->lex_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lex_token *tok
|
struct lex_token *tok = lex_token_create_with_string(
|
||||||
= lex_token_create_with_string(type, fx_string_get_cstr(tmp));
|
type,
|
||||||
|
fx_string_get_cstr(tmp));
|
||||||
|
|
||||||
*out = tok;
|
*out = tok;
|
||||||
return BSHELL_SUCCESS;
|
return BSHELL_SUCCESS;
|
||||||
@@ -867,13 +917,15 @@ enum bshell_status read_word(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (char_can_begin_symbol(ctx, c)) {
|
const char *s = fx_string_get_cstr(tmp);
|
||||||
done = true;
|
if (number_recog && string_is_valid_number(s, NULL, NULL)) {
|
||||||
break;
|
if (c == '.') {
|
||||||
|
fx_string_append_wc(tmp, c);
|
||||||
|
set_token_end(ctx);
|
||||||
|
advance_char(ctx);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *s = fx_string_get_cstr(tmp);
|
|
||||||
if (number_recog && string_is_valid_number(s, NULL)) {
|
|
||||||
if (char_can_begin_symbol_in_state(
|
if (char_can_begin_symbol_in_state(
|
||||||
ctx,
|
ctx,
|
||||||
c,
|
c,
|
||||||
@@ -883,6 +935,11 @@ enum bshell_status read_word(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (char_can_begin_symbol(ctx, c)) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fx_wchar_is_alpha(c)) {
|
if (!fx_wchar_is_alpha(c)) {
|
||||||
op = get_operator_with_string(ctx, s);
|
op = get_operator_with_string(ctx, s);
|
||||||
if (op != TKOP_NONE) {
|
if (op != TKOP_NONE) {
|
||||||
@@ -1321,8 +1378,10 @@ static void discard_all_tokens(struct lex_ctx *ctx)
|
|||||||
{
|
{
|
||||||
fx_queue_entry *cur = fx_queue_first(&ctx->lex_tokens);
|
fx_queue_entry *cur = fx_queue_first(&ctx->lex_tokens);
|
||||||
while (cur) {
|
while (cur) {
|
||||||
struct lex_token *tok
|
struct lex_token *tok = fx_unbox(
|
||||||
= fx_unbox(struct lex_token, cur, tok_entry);
|
struct lex_token,
|
||||||
|
cur,
|
||||||
|
tok_entry);
|
||||||
if (tok->tok_type == TOK_LINEFEED) {
|
if (tok->tok_type == TOK_LINEFEED) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,18 +20,19 @@ static enum bshell_status statement_hyphen(struct lex_ctx *ctx)
|
|||||||
|
|
||||||
unsigned int token_type = TOK_WORD;
|
unsigned int token_type = TOK_WORD;
|
||||||
|
|
||||||
if (convert_word_to_int(tok)) {
|
if (convert_word_to_number(tok)) {
|
||||||
token_type = TOK_INT;
|
token_type = tok->tok_type;
|
||||||
|
|
||||||
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
/* because of APPEND_HYPHEN (which is needed to ensure operator
|
||||||
* tokens are detected properly), the resulting number will be
|
* tokens are detected properly), the resulting number will be
|
||||||
* negative.
|
* negative.
|
||||||
* this token will be preceded by a HYPHEN token, so the number
|
* this token will be preceded by a HYPHEN token, so the number
|
||||||
* must be positive */
|
* must be positive */
|
||||||
tok->tok_int *= -1;
|
fx_value neg = FX_INT(-1);
|
||||||
|
fx_value_multiply(&tok->tok_number, &neg, &tok->tok_number);
|
||||||
push_symbol(ctx, SYM_HYPHEN);
|
push_symbol(ctx, SYM_HYPHEN);
|
||||||
} else if (convert_word_to_operator(ctx, tok)) {
|
} else if (convert_word_to_operator(ctx, tok)) {
|
||||||
token_type = TOK_OPERATOR;
|
token_type = tok->tok_operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_lex_state_transition(ctx, token_type);
|
handle_lex_state_transition(ctx, token_type);
|
||||||
@@ -114,8 +115,8 @@ static enum bshell_status statement_word(struct lex_ctx *ctx)
|
|||||||
|
|
||||||
if (enable_keywords && convert_word_to_keyword(word)) {
|
if (enable_keywords && convert_word_to_keyword(word)) {
|
||||||
token = word->tok_keyword;
|
token = word->tok_keyword;
|
||||||
} else if (convert_word_to_int(word)) {
|
} else if (convert_word_to_number(word)) {
|
||||||
token = TOK_INT;
|
token = word->tok_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_lex_state_transition(ctx, token);
|
handle_lex_state_transition(ctx, token);
|
||||||
@@ -163,13 +164,25 @@ static const struct lex_state_link links[] = {
|
|||||||
LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0),
|
LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0),
|
||||||
/* arithmetic tokens */
|
/* arithmetic tokens */
|
||||||
LINK_CHANGE(TOK_KEYWORD, LEX_STATE_ARITHMETIC),
|
LINK_CHANGE(TOK_KEYWORD, LEX_STATE_ARITHMETIC),
|
||||||
|
LINK_CHANGE(SYM_SQUOTE, LEX_STATE_ARITHMETIC),
|
||||||
LINK_CHANGE(TOK_INT, LEX_STATE_ARITHMETIC),
|
LINK_CHANGE(TOK_INT, LEX_STATE_ARITHMETIC),
|
||||||
|
LINK_CHANGE(TOK_DOUBLE, LEX_STATE_ARITHMETIC),
|
||||||
LINK_PUSH(SYM_DOLLAR, LEX_STATE_ARITHMETIC, 0),
|
LINK_PUSH(SYM_DOLLAR, LEX_STATE_ARITHMETIC, 0),
|
||||||
LINK_PUSH(SYM_DOLLAR_LEFT_BRACE, LEX_STATE_ARITHMETIC, 0),
|
LINK_PUSH_WITH_TERM(
|
||||||
|
SYM_DOLLAR_LEFT_BRACE,
|
||||||
|
LEX_STATE_ARITHMETIC,
|
||||||
|
0,
|
||||||
|
SYM_RIGHT_BRACE),
|
||||||
LINK_CHANGE(SYM_AT_LEFT_BRACE, LEX_STATE_ARITHMETIC),
|
LINK_CHANGE(SYM_AT_LEFT_BRACE, LEX_STATE_ARITHMETIC),
|
||||||
LINK_PUSH(SYM_AT_LEFT_BRACE, LEX_STATE_HASHTABLE, 0),
|
LINK_CHANGE(SYM_AT_LEFT_PAREN, LEX_STATE_ARITHMETIC),
|
||||||
|
LINK_PUSH_WITH_TERM(
|
||||||
|
SYM_AT_LEFT_BRACE,
|
||||||
|
LEX_STATE_HASHTABLE,
|
||||||
|
0,
|
||||||
|
SYM_RIGHT_BRACE),
|
||||||
LINK_PUSH(SYM_AT, LEX_STATE_ARITHMETIC, 0),
|
LINK_PUSH(SYM_AT, LEX_STATE_ARITHMETIC, 0),
|
||||||
LINK_CHANGE(SYM_LEFT_PAREN, LEX_STATE_ARITHMETIC),
|
LINK_CHANGE(SYM_LEFT_PAREN, LEX_STATE_ARITHMETIC),
|
||||||
|
LINK_CHANGE(SYM_LEFT_BRACKET, LEX_STATE_ARITHMETIC),
|
||||||
LINK_CHANGE(SYM_BANG, LEX_STATE_ARITHMETIC),
|
LINK_CHANGE(SYM_BANG, LEX_STATE_ARITHMETIC),
|
||||||
LINK_PUSH_WITH_TERM(
|
LINK_PUSH_WITH_TERM(
|
||||||
SYM_LEFT_PAREN,
|
SYM_LEFT_PAREN,
|
||||||
@@ -178,7 +191,11 @@ static const struct lex_state_link links[] = {
|
|||||||
SYM_RIGHT_PAREN),
|
SYM_RIGHT_PAREN),
|
||||||
|
|
||||||
/* statement tokens */
|
/* statement tokens */
|
||||||
LINK_PUSH(SYM_LEFT_BRACE, LEX_STATE_STATEMENT, 0),
|
LINK_PUSH_WITH_TERM(
|
||||||
|
SYM_LEFT_BRACE,
|
||||||
|
LEX_STATE_STATEMENT,
|
||||||
|
0,
|
||||||
|
SYM_RIGHT_BRACE),
|
||||||
LINK_PUSH_WITH_TERM(
|
LINK_PUSH_WITH_TERM(
|
||||||
SYM_DOLLAR_LEFT_PAREN,
|
SYM_DOLLAR_LEFT_PAREN,
|
||||||
LEX_STATE_STATEMENT,
|
LEX_STATE_STATEMENT,
|
||||||
@@ -213,6 +230,7 @@ static const unsigned int symbols[] = {
|
|||||||
SYM_DQUOTE,
|
SYM_DQUOTE,
|
||||||
SYM_HASH,
|
SYM_HASH,
|
||||||
SYM_AT,
|
SYM_AT,
|
||||||
|
SYM_AT_LEFT_PAREN,
|
||||||
SYM_AT_LEFT_BRACE,
|
SYM_AT_LEFT_BRACE,
|
||||||
SYM_PIPE,
|
SYM_PIPE,
|
||||||
SYM_COMMA,
|
SYM_COMMA,
|
||||||
|
|||||||
+77
-53
@@ -47,8 +47,10 @@ static bool finalise_expr(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct op_ast_node *node
|
struct op_ast_node *node = fx_unbox(
|
||||||
= fx_unbox(struct op_ast_node, entry, n_base.n_entry);
|
struct op_ast_node,
|
||||||
|
entry,
|
||||||
|
n_base.n_entry);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
/* this should never happen */
|
/* this should never happen */
|
||||||
return false;
|
return false;
|
||||||
@@ -72,8 +74,10 @@ static bool finalise_expr(
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct ast_node *item
|
struct ast_node *item = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, entry, n_entry);
|
struct ast_node,
|
||||||
|
entry,
|
||||||
|
n_entry);
|
||||||
fx_queue_entry *next = fx_queue_next(entry);
|
fx_queue_entry *next = fx_queue_next(entry);
|
||||||
fx_queue_delete(&ctx->expr_out_queue, entry);
|
fx_queue_delete(&ctx->expr_out_queue, entry);
|
||||||
|
|
||||||
@@ -115,12 +119,14 @@ static bool finalise_expr(
|
|||||||
|
|
||||||
if (op->op_arity == OPA_BINARY) {
|
if (op->op_arity == OPA_BINARY) {
|
||||||
tmp = fx_queue_pop_back(&q);
|
tmp = fx_queue_pop_back(&q);
|
||||||
op_node->n_left
|
op_node->n_left = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, tmp, n_entry);
|
struct ast_node,
|
||||||
|
tmp,
|
||||||
|
n_entry);
|
||||||
|
|
||||||
if (op_node->n_left) {
|
if (op_node->n_left) {
|
||||||
op_node->n_left->n_parent
|
op_node->n_left->n_parent = (struct ast_node *)
|
||||||
= (struct ast_node *)op_node;
|
op_node;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
ast_node_extend_bounds_recursive(
|
ast_node_extend_bounds_recursive(
|
||||||
@@ -248,8 +254,8 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
|
|
||||||
parse_linefeed(ctx);
|
parse_linefeed(ctx);
|
||||||
|
|
||||||
struct hashtable_ast_node *table
|
struct hashtable_ast_node *table = (struct hashtable_ast_node *)
|
||||||
= (struct hashtable_ast_node *)ast_node_create(AST_HASHTABLE);
|
ast_node_create(AST_HASHTABLE);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
||||||
return false;
|
return false;
|
||||||
@@ -264,14 +270,14 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
|
|
||||||
parse_linefeed(ctx);
|
parse_linefeed(ctx);
|
||||||
|
|
||||||
struct hashtable_item_ast_node *item
|
struct hashtable_item_ast_node *item = (struct
|
||||||
= (struct hashtable_item_ast_node *)ast_node_create(
|
hashtable_item_ast_node
|
||||||
AST_HASHTABLE_ITEM);
|
*)
|
||||||
|
ast_node_create(AST_HASHTABLE_ITEM);
|
||||||
struct lex_token *tok = NULL;
|
struct lex_token *tok = NULL;
|
||||||
if (parse_word(ctx, &tok)) {
|
if (parse_word(ctx, &tok)) {
|
||||||
struct string_ast_node *v
|
struct string_ast_node *v = (struct string_ast_node *)
|
||||||
= (struct string_ast_node *)ast_node_create(
|
ast_node_create(AST_STRING);
|
||||||
AST_STRING);
|
|
||||||
v->n_value = tok;
|
v->n_value = tok;
|
||||||
item->n_key = (struct ast_node *)v;
|
item->n_key = (struct ast_node *)v;
|
||||||
} else if (!parse_arith_value(ctx, &item->n_key)) {
|
} else if (!parse_arith_value(ctx, &item->n_key)) {
|
||||||
@@ -328,8 +334,8 @@ static bool parse_array(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct array_ast_node *array
|
struct array_ast_node *array = (struct array_ast_node *)ast_node_create(
|
||||||
= (struct array_ast_node *)ast_node_create(AST_ARRAY);
|
AST_ARRAY);
|
||||||
if (!array) {
|
if (!array) {
|
||||||
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
||||||
return false;
|
return false;
|
||||||
@@ -377,8 +383,8 @@ bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
|
|
||||||
discard_token(ctx);
|
discard_token(ctx);
|
||||||
|
|
||||||
struct fstring_ast_node *fstring
|
struct fstring_ast_node *fstring = (struct fstring_ast_node *)
|
||||||
= (struct fstring_ast_node *)ast_node_create(AST_FSTRING);
|
ast_node_create(AST_FSTRING);
|
||||||
if (!fstring) {
|
if (!fstring) {
|
||||||
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
||||||
return false;
|
return false;
|
||||||
@@ -414,29 +420,36 @@ bool parse_arith_value(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
struct lex_token *tok = peek_token(ctx);
|
struct lex_token *tok = peek_token(ctx);
|
||||||
switch (tok->tok_type) {
|
switch (tok->tok_type) {
|
||||||
case TOK_INT: {
|
case TOK_INT: {
|
||||||
struct int_ast_node *v
|
struct int_ast_node *v = (struct int_ast_node *)ast_node_create(
|
||||||
= (struct int_ast_node *)ast_node_create(AST_INT);
|
AST_INT);
|
||||||
v->n_value = claim_token(ctx);
|
v->n_value = claim_token(ctx);
|
||||||
*out = (struct ast_node *)v;
|
*out = (struct ast_node *)v;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TOK_DOUBLE: {
|
case TOK_DOUBLE: {
|
||||||
struct double_ast_node *v
|
struct double_ast_node *v = (struct double_ast_node *)
|
||||||
= (struct double_ast_node *)ast_node_create(AST_DOUBLE);
|
ast_node_create(AST_DOUBLE);
|
||||||
v->n_value = claim_token(ctx);
|
v->n_value = claim_token(ctx);
|
||||||
*out = (struct ast_node *)v;
|
*out = (struct ast_node *)v;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TOK_STRING: {
|
case TOK_STRING: {
|
||||||
struct string_ast_node *v
|
struct string_ast_node *v = (struct string_ast_node *)
|
||||||
= (struct string_ast_node *)ast_node_create(AST_STRING);
|
ast_node_create(AST_STRING);
|
||||||
|
v->n_value = claim_token(ctx);
|
||||||
|
*out = (struct ast_node *)v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case TOK_WORD: {
|
||||||
|
struct word_ast_node *v = (struct word_ast_node *)
|
||||||
|
ast_node_create(AST_WORD);
|
||||||
v->n_value = claim_token(ctx);
|
v->n_value = claim_token(ctx);
|
||||||
*out = (struct ast_node *)v;
|
*out = (struct ast_node *)v;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TOK_VAR: {
|
case TOK_VAR: {
|
||||||
struct var_ast_node *v
|
struct var_ast_node *v = (struct var_ast_node *)ast_node_create(
|
||||||
= (struct var_ast_node *)ast_node_create(AST_VAR);
|
AST_VAR);
|
||||||
v->n_ident = claim_token(ctx);
|
v->n_ident = claim_token(ctx);
|
||||||
*out = (struct ast_node *)v;
|
*out = (struct ast_node *)v;
|
||||||
return true;
|
return true;
|
||||||
@@ -492,20 +505,22 @@ void arith_push_operator(struct expr_parse_ctx *state, struct op_ast_node *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
fx_queue_entry *top
|
fx_queue_entry *top = fx_queue_last(
|
||||||
= fx_queue_last(&state->expr_operator_stack);
|
&state->expr_operator_stack);
|
||||||
if (!top) {
|
if (!top) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast_node *top_node
|
struct ast_node *top_node = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, top, n_entry);
|
struct ast_node,
|
||||||
|
top,
|
||||||
|
n_entry);
|
||||||
const struct operator_info *top_op = NULL;
|
const struct operator_info *top_op = NULL;
|
||||||
|
|
||||||
switch (top_node->n_type) {
|
switch (top_node->n_type) {
|
||||||
case AST_OP: {
|
case AST_OP: {
|
||||||
struct op_ast_node *op_node
|
struct op_ast_node *op_node = (struct op_ast_node *)
|
||||||
= (struct op_ast_node *)top_node;
|
top_node;
|
||||||
top_op = op_node->n_op;
|
top_op = op_node->n_op;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -575,8 +590,8 @@ static bool parse_unary_operator(
|
|||||||
|
|
||||||
expr->expr_prev = EXPR_C_BINARY_OP;
|
expr->expr_prev = EXPR_C_BINARY_OP;
|
||||||
|
|
||||||
struct op_ast_node *op_node
|
struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create(
|
||||||
= (struct op_ast_node *)ast_node_create(AST_OP);
|
AST_OP);
|
||||||
if (!op_node) {
|
if (!op_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -639,8 +654,8 @@ static bool parse_binary_operator(
|
|||||||
|
|
||||||
expr->expr_prev = EXPR_C_BINARY_OP;
|
expr->expr_prev = EXPR_C_BINARY_OP;
|
||||||
|
|
||||||
struct op_ast_node *op_node
|
struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create(
|
||||||
= (struct op_ast_node *)ast_node_create(AST_OP);
|
AST_OP);
|
||||||
if (!op_node) {
|
if (!op_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -669,8 +684,8 @@ static bool parse_comma(struct parse_ctx *ctx, struct expr_parse_ctx *expr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct array_ast_node *array
|
struct array_ast_node *array = (struct array_ast_node *)ast_node_create(
|
||||||
= (struct array_ast_node *)ast_node_create(AST_ARRAY);
|
AST_ARRAY);
|
||||||
if (!array) {
|
if (!array) {
|
||||||
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
||||||
ast_node_destroy(item);
|
ast_node_destroy(item);
|
||||||
@@ -706,8 +721,10 @@ static void dump_expr_ctx(struct expr_parse_ctx *expr)
|
|||||||
printf("op stack:\n");
|
printf("op stack:\n");
|
||||||
fx_queue_entry *entry = fx_queue_first(&expr->expr_operator_stack);
|
fx_queue_entry *entry = fx_queue_first(&expr->expr_operator_stack);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct ast_node *node
|
struct ast_node *node = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, entry, n_entry);
|
struct ast_node,
|
||||||
|
entry,
|
||||||
|
n_entry);
|
||||||
print_ast_node(node);
|
print_ast_node(node);
|
||||||
entry = fx_queue_next(entry);
|
entry = fx_queue_next(entry);
|
||||||
}
|
}
|
||||||
@@ -715,8 +732,10 @@ static void dump_expr_ctx(struct expr_parse_ctx *expr)
|
|||||||
printf("out queue:\n");
|
printf("out queue:\n");
|
||||||
entry = fx_queue_first(&expr->expr_out_queue);
|
entry = fx_queue_first(&expr->expr_out_queue);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct ast_node *node
|
struct ast_node *node = fx_unbox(
|
||||||
= fx_unbox(struct ast_node, entry, n_entry);
|
struct ast_node,
|
||||||
|
entry,
|
||||||
|
n_entry);
|
||||||
print_ast_node(node);
|
print_ast_node(node);
|
||||||
entry = fx_queue_next(entry);
|
entry = fx_queue_next(entry);
|
||||||
}
|
}
|
||||||
@@ -755,17 +774,16 @@ bool parse_arith_expr(
|
|||||||
|
|
||||||
switch (tok->tok_type) {
|
switch (tok->tok_type) {
|
||||||
case TOK_LINEFEED:
|
case TOK_LINEFEED:
|
||||||
|
expr.expr_prev_symbol = tok->tok_type;
|
||||||
expr.expr_done = true;
|
expr.expr_done = true;
|
||||||
break;
|
break;
|
||||||
case TOK_WORD: {
|
case TOK_WORD: {
|
||||||
if (!can_use_command(&expr)) {
|
if (!can_use_command(&expr)) {
|
||||||
report_error(
|
expr.expr_fail = !parse_operand(ctx, &expr);
|
||||||
ctx,
|
|
||||||
"expected a value expression");
|
|
||||||
expr.expr_fail = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr.expr_prev_symbol = tok->tok_type;
|
||||||
struct ast_node *value = NULL;
|
struct ast_node *value = NULL;
|
||||||
if (!parse_command(ctx, &value)) {
|
if (!parse_command(ctx, &value)) {
|
||||||
expr.expr_fail = true;
|
expr.expr_fail = true;
|
||||||
@@ -783,10 +801,12 @@ bool parse_arith_expr(
|
|||||||
case TOK_DOUBLE:
|
case TOK_DOUBLE:
|
||||||
case TOK_STRING:
|
case TOK_STRING:
|
||||||
case TOK_STR_START:
|
case TOK_STR_START:
|
||||||
|
expr.expr_prev_symbol = tok->tok_type;
|
||||||
expr.expr_fail = !parse_operand(ctx, &expr);
|
expr.expr_fail = !parse_operand(ctx, &expr);
|
||||||
expr.expr_prev_symbol = tok->tok_type;
|
expr.expr_prev_symbol = tok->tok_type;
|
||||||
break;
|
break;
|
||||||
case TOK_OPERATOR:
|
case TOK_OPERATOR:
|
||||||
|
expr.expr_prev_symbol = tok->tok_operator;
|
||||||
switch (tok->tok_operator) {
|
switch (tok->tok_operator) {
|
||||||
/* these two are special cases, as they are both
|
/* these two are special cases, as they are both
|
||||||
* unary AND binary operators */
|
* unary AND binary operators */
|
||||||
@@ -805,17 +825,21 @@ bool parse_arith_expr(
|
|||||||
break;
|
break;
|
||||||
case TKOP_BNOT:
|
case TKOP_BNOT:
|
||||||
case TKOP_NOT:
|
case TKOP_NOT:
|
||||||
expr.expr_fail
|
expr.expr_fail = !parse_unary_operator(
|
||||||
= !parse_unary_operator(ctx, &expr);
|
ctx,
|
||||||
|
&expr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
expr.expr_fail
|
expr.expr_fail = !parse_binary_operator(
|
||||||
= !parse_binary_operator(ctx, &expr);
|
ctx,
|
||||||
|
&expr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
expr.expr_prev_symbol = tok->tok_operator;
|
expr.expr_prev_symbol = tok->tok_operator;
|
||||||
break;
|
break;
|
||||||
case TOK_SYMBOL:
|
case TOK_SYMBOL:
|
||||||
|
expr.expr_prev_symbol = tok->tok_symbol;
|
||||||
|
|
||||||
switch (tok->tok_symbol) {
|
switch (tok->tok_symbol) {
|
||||||
case SYM_SEMICOLON:
|
case SYM_SEMICOLON:
|
||||||
case SYM_AMPERSAND:
|
case SYM_AMPERSAND:
|
||||||
@@ -848,6 +872,7 @@ bool parse_arith_expr(
|
|||||||
case SYM_DOLLAR_LEFT_PAREN:
|
case SYM_DOLLAR_LEFT_PAREN:
|
||||||
case SYM_AT_LEFT_PAREN:
|
case SYM_AT_LEFT_PAREN:
|
||||||
case SYM_AT_LEFT_BRACE:
|
case SYM_AT_LEFT_BRACE:
|
||||||
|
case SYM_LEFT_BRACE:
|
||||||
expr.expr_fail = !parse_operand(ctx, &expr);
|
expr.expr_fail = !parse_operand(ctx, &expr);
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
@@ -867,7 +892,6 @@ bool parse_arith_expr(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr.expr_prev_symbol = tok->tok_symbol;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
report_error(
|
report_error(
|
||||||
|
|||||||
@@ -6,23 +6,44 @@ bool parse_block(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_linefeed(ctx);
|
||||||
|
|
||||||
struct block_ast_node *block
|
struct block_ast_node *block
|
||||||
= (struct block_ast_node *)ast_node_create(AST_BLOCK);
|
= (struct block_ast_node *)ast_node_create(AST_BLOCK);
|
||||||
|
|
||||||
|
bool ok = true;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
if (parse_symbol(ctx, SYM_RIGHT_BRACE)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
parse_linefeed(ctx);
|
parse_linefeed(ctx);
|
||||||
|
|
||||||
|
struct ast_node *stmt = NULL;
|
||||||
|
if (!parse_statement(ctx, &stmt)) {
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_queue_push_back(&block->n_statements, &stmt->n_entry);
|
||||||
|
|
||||||
if (parse_symbol(ctx, SYM_RIGHT_BRACE)) {
|
if (parse_symbol(ctx, SYM_RIGHT_BRACE)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ast_node *stmt = NULL;
|
if (!parse_linefeed(ctx) && !parse_symbol(ctx, SYM_SEMICOLON)) {
|
||||||
if (!parse_statement(ctx, &stmt)) {
|
report_error(
|
||||||
ast_node_destroy((struct ast_node *)block);
|
ctx,
|
||||||
return false;
|
"expected `;`, `}`, or linefeed after "
|
||||||
|
"statement");
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fx_queue_push_back(&block->n_statements, &stmt->n_entry);
|
if (!ok) {
|
||||||
|
ast_node_destroy((struct ast_node *)block);
|
||||||
|
block = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = (struct ast_node *)block;
|
*out = (struct ast_node *)block;
|
||||||
|
|||||||
@@ -155,19 +155,3 @@ bool parse_var(struct parse_ctx *ctx, struct lex_token **out)
|
|||||||
*out = claim_token(ctx);
|
*out = claim_token(ctx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_int(struct parse_ctx *ctx, long long *out)
|
|
||||||
{
|
|
||||||
struct lex_token *tok = peek_token(ctx);
|
|
||||||
if (!tok) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok->tok_type != TOK_INT) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = tok->tok_int;
|
|
||||||
discard_token(ctx);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ static bool add_branch(
|
|||||||
struct ast_node *cond,
|
struct ast_node *cond,
|
||||||
struct ast_node *body)
|
struct ast_node *body)
|
||||||
{
|
{
|
||||||
struct if_branch_ast_node *branch
|
struct if_branch_ast_node *branch = (struct if_branch_ast_node *)
|
||||||
= (struct if_branch_ast_node *)ast_node_create(AST_IF_BRANCH);
|
ast_node_create(AST_IF_BRANCH);
|
||||||
if (!branch) {
|
if (!branch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -47,8 +47,8 @@ bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct if_ast_node *if_group
|
struct if_ast_node *if_group = (struct if_ast_node *)ast_node_create(
|
||||||
= (struct if_ast_node *)ast_node_create(AST_IF);
|
AST_IF);
|
||||||
if (!if_group) {
|
if (!if_group) {
|
||||||
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
ctx->p_status = BSHELL_ERR_NO_MEMORY;
|
||||||
ast_node_destroy(if_cond);
|
ast_node_destroy(if_cond);
|
||||||
@@ -70,6 +70,13 @@ bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
if (parse_keyword(ctx, KW_ELSE)) {
|
if (parse_keyword(ctx, KW_ELSE)) {
|
||||||
done = true;
|
done = true;
|
||||||
} else if (parse_keyword(ctx, KW_ELSEIF)) {
|
} else if (parse_keyword(ctx, KW_ELSEIF)) {
|
||||||
|
if (!parse_symbol(ctx, SYM_LEFT_PAREN)) {
|
||||||
|
report_error(
|
||||||
|
ctx,
|
||||||
|
"expected `(` after `elseif`");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parse_expr(ctx, &cond)) {
|
if (!parse_expr(ctx, &cond)) {
|
||||||
report_error(
|
report_error(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -77,6 +84,14 @@ bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
|
|||||||
ast_node_destroy((struct ast_node *)if_group);
|
ast_node_destroy((struct ast_node *)if_group);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) {
|
||||||
|
report_error(
|
||||||
|
ctx,
|
||||||
|
"expected `)` after elseif-condition");
|
||||||
|
ast_node_destroy(if_cond);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
done = true;
|
done = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define IVY_LANG_LEX_H_
|
#define IVY_LANG_LEX_H_
|
||||||
|
|
||||||
#include <fx/queue.h>
|
#include <fx/queue.h>
|
||||||
|
#include <fx/value.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct char_cell {
|
struct char_cell {
|
||||||
@@ -129,8 +130,7 @@ struct lex_token {
|
|||||||
enum token_keyword tok_keyword;
|
enum token_keyword tok_keyword;
|
||||||
enum token_symbol tok_symbol;
|
enum token_symbol tok_symbol;
|
||||||
enum token_operator tok_operator;
|
enum token_operator tok_operator;
|
||||||
long long tok_int;
|
fx_value tok_number;
|
||||||
double tok_double;
|
|
||||||
char *tok_str;
|
char *tok_str;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,328 @@
|
|||||||
|
#include "cmdcall.h"
|
||||||
|
|
||||||
|
#include "../command/alias.h"
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../runtime/pipeline.h"
|
||||||
|
#include "../status.h"
|
||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/reflection/assembly.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/reflection/type.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/term/print.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
enum cmdcall_type {
|
||||||
|
CMDCALL_NONE = 0,
|
||||||
|
CMDCALL_CMDLET,
|
||||||
|
CMDCALL_NATIVE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bshell_cmdcall_p {
|
||||||
|
enum cmdcall_type cmd_type;
|
||||||
|
bshell_command *cmd_target;
|
||||||
|
char *cmd_native_path;
|
||||||
|
bool cmd_initialised;
|
||||||
|
FX_VECTOR_DECLARE(fx_value, cmd_args);
|
||||||
|
fx_array *cmd_args_processed;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const fx_assembly *bshell_assembly_get(void);
|
||||||
|
|
||||||
|
static void cmdcall_fini(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_cmdcall_p *cmdcall = priv;
|
||||||
|
|
||||||
|
if (cmdcall->cmd_native_path) {
|
||||||
|
free(cmdcall->cmd_native_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdcall->cmd_args_processed) {
|
||||||
|
fx_array_unref(cmdcall->cmd_args_processed);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cmdcall->cmd_args.count; i++) {
|
||||||
|
fx_value_unset(&cmdcall->cmd_args.items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_vector_destroy(cmdcall->cmd_args, NULL);
|
||||||
|
|
||||||
|
if (cmdcall->cmd_target) {
|
||||||
|
bshell_command_end_processing(cmdcall->cmd_target);
|
||||||
|
bshell_command_unref(cmdcall->cmd_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status cmdcall_push_arg(
|
||||||
|
struct bshell_cmdcall_p *cmdcall,
|
||||||
|
fx_value arg)
|
||||||
|
{
|
||||||
|
fx_value *slot = fx_vector_emplace_back(cmdcall->cmd_args, NULL);
|
||||||
|
fx_value_copy(slot, &arg);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *get_arg(struct bshell_cmdcall_p *cmdcall, size_t index)
|
||||||
|
{
|
||||||
|
if (index >= cmdcall->cmd_args.count) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cmdcall->cmd_args.items[cmdcall->cmd_args.count - index - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bshell_command *find_call_target(const char *name)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
#define VERB_MAX 32
|
||||||
|
const char *hyphen = strchr(name, '-');
|
||||||
|
if (!hyphen) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *noun = hyphen + 1;
|
||||||
|
|
||||||
|
size_t verb_length = hyphen - name;
|
||||||
|
if (verb_length >= VERB_MAX) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char verb[VERB_MAX] = {};
|
||||||
|
memcpy(verb, name, verb_length);
|
||||||
|
for (size_t i = 0; i < verb_length; i++) {
|
||||||
|
verb[i] = tolower(verb[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_verb *verb_info = bshell_verb_get_by_name(verb);
|
||||||
|
if (!verb_info) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_verb_id verb_id = bshell_verb_get_id(verb_info);
|
||||||
|
fx_string *target_name = fx_string_create();
|
||||||
|
fx_string *call_name = fx_string_create_from_cstr(name);
|
||||||
|
fx_string_transform_lowercase(call_name);
|
||||||
|
|
||||||
|
const fx_assembly *self = bshell_assembly_get();
|
||||||
|
fx_iterator *it = fx_assembly_get_types(self);
|
||||||
|
fx_foreach(v, it)
|
||||||
|
{
|
||||||
|
fx_type *ty = NULL;
|
||||||
|
fx_value_get_object(&v, &ty);
|
||||||
|
const char *ty_name = fx_type_get_name(ty);
|
||||||
|
bshell_command_class *cmd = fx_type_get_interface(
|
||||||
|
ty,
|
||||||
|
BSHELL_TYPE_COMMAND);
|
||||||
|
if (!cmd || !cmd->c_get_callable_name_static) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd->c_get_callable_name(
|
||||||
|
|
||||||
|
if (fx_strcmp_nocase(cmdlet->c_noun, noun) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx_object_create(fx_type_get_id(ty));
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
#undef VERB_MAX
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bshell_command *__resolve_call_target(
|
||||||
|
const char *callable_name,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
return bshell_runtime_find_command(rt, callable_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status resolve_call_target(
|
||||||
|
struct bshell_cmdcall_p *cmdcall,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
if (cmdcall->cmd_type != CMDCALL_NONE) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value *cmd_name_v = fx_array_get_ref(cmdcall->cmd_args_processed, 0);
|
||||||
|
if (!cmd_name_v) {
|
||||||
|
return BSHELL_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_string *cmd_name_s = NULL;
|
||||||
|
fx_value_get_object(cmd_name_v, &cmd_name_s);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
|
||||||
|
bshell_command *cmd = bshell_runtime_find_command(
|
||||||
|
rt,
|
||||||
|
cmd_name_cstr);
|
||||||
|
if (!cmd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_alias_class *alias = fx_object_get_interface(
|
||||||
|
cmd,
|
||||||
|
BSHELL_TYPE_ALIAS);
|
||||||
|
if (alias) {
|
||||||
|
fx_string_clear(cmd_name_s);
|
||||||
|
fx_string_append_cstr(cmd_name_s, alias->a_target_name);
|
||||||
|
bshell_command_unref(cmd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdcall->cmd_target = cmd;
|
||||||
|
cmdcall->cmd_type = CMDCALL_CMDLET;
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cmd_name_cstr = fx_string_get_cstr(cmd_name_s);
|
||||||
|
fx_printf(
|
||||||
|
"[bold,bright_red]%s: The term '%s' is not recognised as a "
|
||||||
|
"name of a cmdlet, "
|
||||||
|
"function, script file, or executable program.[reset]\n",
|
||||||
|
cmd_name_cstr,
|
||||||
|
cmd_name_cstr);
|
||||||
|
return BSHELL_ERR_NO_ENTRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_args(struct bshell_cmdcall_p *cmdcall)
|
||||||
|
{
|
||||||
|
if (cmdcall->cmd_args_processed) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stringstream *str = fx_stringstream_create();
|
||||||
|
if (!str) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdcall->cmd_args_processed = fx_array_create();
|
||||||
|
if (!cmdcall->cmd_args_processed) {
|
||||||
|
fx_stringstream_unref(str);
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = cmdcall->cmd_args.count - 1; i >= 0; i--) {
|
||||||
|
fx_stringstream_reset(str);
|
||||||
|
fx_value_to_string(&cmdcall->cmd_args.items[i], str, NULL);
|
||||||
|
fx_string *arg_str = fx_string_create_from_cstr(
|
||||||
|
fx_stringstream_ptr(str));
|
||||||
|
fx_array_push_back(
|
||||||
|
cmdcall->cmd_args_processed,
|
||||||
|
FX_VALUE_OBJECT(arg_str));
|
||||||
|
fx_string_unref(arg_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stringstream_unref(str);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status cmdcall_resolve(
|
||||||
|
struct bshell_cmdcall_p *cmdcall,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
enum bshell_status status = process_args(cmdcall);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = resolve_call_target(cmdcall, rt);
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_command_set_args_reverse(
|
||||||
|
cmdcall->cmd_target,
|
||||||
|
cmdcall->cmd_args.items,
|
||||||
|
cmdcall->cmd_args.count);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status cmdcall_execute(struct bshell_cmdcall_p *cmdcall)
|
||||||
|
{
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status cmdcall_process_record(
|
||||||
|
struct bshell_cmdcall_p *cmdcall,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
if (!cmdcall->cmd_target) {
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmdcall->cmd_initialised) {
|
||||||
|
bshell_command_begin_processing(cmdcall->cmd_target);
|
||||||
|
cmdcall->cmd_initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bshell_command_process_record(cmdcall->cmd_target, pipeline, rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_cmdcall_push_arg(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
fx_value arg)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_CMDCALL,
|
||||||
|
cmdcall_push_arg,
|
||||||
|
cmdcall,
|
||||||
|
arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_cmdcall_resolve(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_CMDCALL,
|
||||||
|
cmdcall_resolve,
|
||||||
|
cmdcall,
|
||||||
|
rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_cmdcall_execute(bshell_cmdcall *cmdcall)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(
|
||||||
|
BSHELL_TYPE_CMDCALL,
|
||||||
|
cmdcall_execute,
|
||||||
|
cmdcall);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_cmdcall_process_record(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_CMDCALL,
|
||||||
|
cmdcall_process_record,
|
||||||
|
cmdcall,
|
||||||
|
pipeline,
|
||||||
|
rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_cmdcall)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_CONSTRUCTOR("create", bshell_cmdcall_create, 0, FX_TYPE_VOID);
|
||||||
|
FX_TYPE_CLASS_END(bshell_cmdcall)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_cmdcall)
|
||||||
|
FX_TYPE_ID(0x08aeb275, 0xc09b, 0x4c3a, 0xa8df, 0xd9fba0bb4571);
|
||||||
|
FX_TYPE_NAME("bshell.cmdcall");
|
||||||
|
FX_TYPE_CLASS(bshell_cmdcall_class);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_cmdcall_p);
|
||||||
|
FX_TYPE_INSTANCE_FINI(cmdcall_fini);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_cmdcall)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef RUNTIME_CMDCALL_H_
|
||||||
|
#define RUNTIME_CMDCALL_H_
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_CMDCALL (bshell_cmdcall_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_cmdcall);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_cmdcall)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_cmdcall)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_cmdcall_get_type(void);
|
||||||
|
|
||||||
|
FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_cmdcall, BSHELL_TYPE_CMDCALL);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_cmdcall_push_arg(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
fx_value arg);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_cmdcall_resolve(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
struct bshell_runtime *rt);
|
||||||
|
extern enum bshell_status bshell_cmdcall_process_record(
|
||||||
|
bshell_cmdcall *cmdcall,
|
||||||
|
FX_TYPE_FWDREF(bshell_pipeline) * pipeline,
|
||||||
|
struct bshell_runtime *rt);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,459 @@
|
|||||||
|
#include "../format/format.h"
|
||||||
|
#include "../status.h"
|
||||||
|
#include "cmdcall.h"
|
||||||
|
#include "pipeline.h"
|
||||||
|
#include "runtime.h"
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/collections/hashtable.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static enum bshell_status eval_instruction(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
struct runtime_scope *scope,
|
||||||
|
bshell_instruction instr)
|
||||||
|
{
|
||||||
|
fx_value x, y, z;
|
||||||
|
enum bshell_opcode opcode;
|
||||||
|
fx_status status;
|
||||||
|
enum bshell_status bstatus = BSHELL_SUCCESS;
|
||||||
|
uint32_t arg;
|
||||||
|
fx_type_id type;
|
||||||
|
fx_value *pool_value = NULL;
|
||||||
|
bshell_variable *var = NULL;
|
||||||
|
const char *s = NULL;
|
||||||
|
bshell_instruction_decode(instr, &opcode, &arg);
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case OPCODE_LDC_INT:
|
||||||
|
x = FX_INT(arg);
|
||||||
|
runtime_scope_push_value(scope, &x);
|
||||||
|
fx_value_unset(&x);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDC_FP:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_DOUBLE);
|
||||||
|
if (pool_value) {
|
||||||
|
runtime_scope_push_value(scope, pool_value);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "RUNTIME: invalid ldc.fp operand\n");
|
||||||
|
return BSHELL_ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_LDC_STR:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_STRING);
|
||||||
|
if (!pool_value) {
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_CSTR);
|
||||||
|
}
|
||||||
|
if (pool_value) {
|
||||||
|
runtime_scope_push_value(scope, pool_value);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "RUNTIME: invalid ldc.str operand\n");
|
||||||
|
return BSHELL_ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_ADD:
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
y = runtime_scope_pop_value(scope);
|
||||||
|
type = fx_value_get_common_type(&x, &y);
|
||||||
|
if (!type) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: cannot apply operator to operands of "
|
||||||
|
"incompatible type\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
status = fx_value_change_type(&y, &y, type);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: cannot convert operand to the "
|
||||||
|
"necessary type\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
status = fx_value_change_type(&x, &x, type);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: cannot convert operand to the "
|
||||||
|
"necessary type\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
status = fx_value_add(&x, &y, &z);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
runtime_scope_push_value(scope, &z);
|
||||||
|
fx_value_unset(&z);
|
||||||
|
break;
|
||||||
|
case OPCODE_SUB:
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
y = runtime_scope_pop_value(scope);
|
||||||
|
type = fx_value_get_common_type(&x, &y);
|
||||||
|
if (!type) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: cannot apply operator to operands of "
|
||||||
|
"incompatible type\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fx_value_subtract(&x, &y, &z);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
runtime_scope_push_value(scope, &z);
|
||||||
|
fx_value_unset(&z);
|
||||||
|
break;
|
||||||
|
case OPCODE_MUL:
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
y = runtime_scope_pop_value(scope);
|
||||||
|
type = fx_value_get_common_type(&x, &y);
|
||||||
|
if (!type) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: cannot apply operator to operands of "
|
||||||
|
"incompatible type\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fx_value_multiply(&x, &y, &z);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
runtime_scope_push_value(scope, &z);
|
||||||
|
fx_value_unset(&z);
|
||||||
|
break;
|
||||||
|
case OPCODE_DIV:
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
y = runtime_scope_pop_value(scope);
|
||||||
|
status = fx_value_change_type(&x, &x, FX_TYPE_DOUBLE);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fx_value_change_type(&y, &y, FX_TYPE_DOUBLE);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fx_value_divide(&x, &y, &z);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: operands do not support specified "
|
||||||
|
"operator\n");
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
runtime_scope_push_value(scope, &z);
|
||||||
|
fx_value_unset(&z);
|
||||||
|
break;
|
||||||
|
case OPCODE_LDLOCAL:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_STRING);
|
||||||
|
if (!pool_value) {
|
||||||
|
fprintf(stderr, "RUNTIME: invalid ldlocal operand\n");
|
||||||
|
return BSHELL_ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_get_cstr(pool_value, &s);
|
||||||
|
var = bshell_runtime_find_var(rt, s);
|
||||||
|
if (var) {
|
||||||
|
runtime_scope_push_value(
|
||||||
|
scope,
|
||||||
|
bshell_variable_get_value(var));
|
||||||
|
} else {
|
||||||
|
runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDBLOCK:
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK);
|
||||||
|
if (!pool_value) {
|
||||||
|
fprintf(stderr, "RUNTIME: invalid ldblock operand\n");
|
||||||
|
return BSHELL_ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime_scope_push_value(scope, pool_value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPCODE_LDPROP: {
|
||||||
|
/* container */
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
/* property */
|
||||||
|
y = runtime_scope_pop_value(scope);
|
||||||
|
|
||||||
|
const fx_type *ty = fx_type_get_by_id(x.v_type);
|
||||||
|
if (!ty) {
|
||||||
|
fx_value_unset(&x);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stringstream *strm = fx_stringstream_create();
|
||||||
|
fx_value_to_string(&y, strm, NULL);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
|
||||||
|
const fx_property *prop = fx_type_get_property(
|
||||||
|
ty,
|
||||||
|
fx_stringstream_ptr(strm));
|
||||||
|
fx_stringstream_unref(strm);
|
||||||
|
|
||||||
|
if (!prop) {
|
||||||
|
fx_value_unset(&x);
|
||||||
|
runtime_scope_push_value(scope, &FX_VALUE_EMPTY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_property_get_value(prop, &x, &z);
|
||||||
|
fx_value_unset(&x);
|
||||||
|
runtime_scope_push_value(scope, &z);
|
||||||
|
fx_value_unset(&z);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPCODE_STLOCAL:
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
pool_value = bshell_scriptblock_get_pool_value(
|
||||||
|
scope->s_block,
|
||||||
|
arg,
|
||||||
|
FX_TYPE_CSTR);
|
||||||
|
if (!pool_value) {
|
||||||
|
fprintf(stderr, "RUNTIME: invalid stlocal operand\n");
|
||||||
|
return BSHELL_ERR_BAD_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_get_cstr(pool_value, &s);
|
||||||
|
var = bshell_runtime_find_var(rt, s);
|
||||||
|
if (!var) {
|
||||||
|
var = bshell_runtime_define_var(rt, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable_set_value(var, &x);
|
||||||
|
runtime_scope_push_value(scope, &x);
|
||||||
|
fx_value_unset(&x);
|
||||||
|
break;
|
||||||
|
case OPCODE_MK_STR: {
|
||||||
|
fx_string *result = fx_string_create();
|
||||||
|
fx_stringstream *strm = fx_stringstream_create();
|
||||||
|
|
||||||
|
while (arg > 0) {
|
||||||
|
x = runtime_scope_pop_value(scope);
|
||||||
|
fx_stringstream_reset(strm);
|
||||||
|
fx_value_to_string(&x, strm, NULL);
|
||||||
|
fx_string_prepend_cstr(
|
||||||
|
result,
|
||||||
|
fx_stringstream_ptr(strm));
|
||||||
|
fx_value_unset(&x);
|
||||||
|
arg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stringstream_unref(strm);
|
||||||
|
y = FX_VALUE_OBJECT(result);
|
||||||
|
runtime_scope_push_value(scope, &y);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPCODE_MK_HTAB: {
|
||||||
|
fx_hashtable *result = fx_hashtable_create();
|
||||||
|
|
||||||
|
while (arg > 0) {
|
||||||
|
fx_value key = runtime_scope_pop_value(scope);
|
||||||
|
fx_value value = runtime_scope_pop_value(scope);
|
||||||
|
fx_hashtable_put(result, &key, &value);
|
||||||
|
fx_value_unset(&key);
|
||||||
|
fx_value_unset(&value);
|
||||||
|
arg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = FX_VALUE_OBJECT(result);
|
||||||
|
runtime_scope_push_value(scope, &y);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPCODE_MK_ARRAY: {
|
||||||
|
fx_array *result = fx_array_create();
|
||||||
|
|
||||||
|
while (arg > 0) {
|
||||||
|
fx_value value = runtime_scope_pop_value(scope);
|
||||||
|
fx_array_push_front(result, value);
|
||||||
|
fx_value_unset(&value);
|
||||||
|
arg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = FX_VALUE_OBJECT(result);
|
||||||
|
runtime_scope_push_value(scope, &y);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPCODE_LDCMD: {
|
||||||
|
bshell_cmdcall *result = bshell_cmdcall_create();
|
||||||
|
|
||||||
|
while (arg > 0) {
|
||||||
|
fx_value cmd_arg = runtime_scope_pop_value(scope);
|
||||||
|
bshell_cmdcall_push_arg(result, cmd_arg);
|
||||||
|
fx_value_unset(&cmd_arg);
|
||||||
|
arg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bstatus = bshell_cmdcall_resolve(result, rt);
|
||||||
|
if (bstatus != BSHELL_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = FX_VALUE_OBJECT(result);
|
||||||
|
runtime_scope_push_value(scope, &y);
|
||||||
|
fx_value_unset(&y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPCODE_PEXEC: {
|
||||||
|
bshell_pipeline *pipeline = bshell_pipeline_create();
|
||||||
|
bool single = (arg == 1);
|
||||||
|
while (arg > 0) {
|
||||||
|
fx_value cmd = runtime_scope_pop_value(scope);
|
||||||
|
bshell_cmdcall *cmdcall = NULL;
|
||||||
|
if (fx_value_is_type(&cmd, BSHELL_TYPE_CMDCALL)) {
|
||||||
|
fx_value_get_object(&cmd, &cmdcall);
|
||||||
|
bshell_pipeline_add_cmdcall(pipeline, cmdcall);
|
||||||
|
} else {
|
||||||
|
bshell_pipeline_add_input_value(
|
||||||
|
pipeline,
|
||||||
|
cmd,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&cmd);
|
||||||
|
arg--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int end_of_data = 0;
|
||||||
|
bool columns_initialised = false;
|
||||||
|
fx_value record = FX_VALUE_EMPTY;
|
||||||
|
struct table_format_ctx table_ctx;
|
||||||
|
table_format_ctx_init(&table_ctx, fx_stdout);
|
||||||
|
while (1) {
|
||||||
|
bstatus = bshell_pipeline_pump_record(
|
||||||
|
pipeline,
|
||||||
|
rt,
|
||||||
|
&record,
|
||||||
|
&end_of_data);
|
||||||
|
if (bstatus != BSHELL_SUCCESS || end_of_data) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!record.v_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!columns_initialised) {
|
||||||
|
const fx_type *ty = fx_type_get_by_id(
|
||||||
|
record.v_type);
|
||||||
|
table_format_ctx_prepare_columns_from_format(
|
||||||
|
&table_ctx,
|
||||||
|
ty,
|
||||||
|
NULL);
|
||||||
|
table_format_ctx_print_headers(&table_ctx);
|
||||||
|
columns_initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
table_format_ctx_print_record(&table_ctx, &record);
|
||||||
|
fx_value_unset(&record);
|
||||||
|
}
|
||||||
|
|
||||||
|
table_format_ctx_cleanup(&table_ctx);
|
||||||
|
bshell_pipeline_unref(pipeline);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fprintf(stderr,
|
||||||
|
"RUNTIME: encountered unknown opcode %02x\n",
|
||||||
|
opcode);
|
||||||
|
return BSHELL_ERR_BAD_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope->s_ip++;
|
||||||
|
return bstatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_value runtime_eval(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
while (status == BSHELL_SUCCESS) {
|
||||||
|
struct runtime_scope *scope = runtime_get_scope(rt);
|
||||||
|
if (scope->s_ip >= scope->s_nr_instr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_instruction instr = scope->s_instr[scope->s_ip];
|
||||||
|
status = eval_instruction(rt, scope, instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct runtime_scope *scope = runtime_get_scope(rt);
|
||||||
|
return runtime_scope_pop_value(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value bshell_runtime_eval_global(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
runtime_scope_set_block(rt->rt_global, block);
|
||||||
|
return runtime_eval(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value bshell_runtime_eval_script(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
runtime_push_scope(rt, RUNTIME_SCOPE_SCRIPT, block);
|
||||||
|
fx_value result = runtime_eval(rt);
|
||||||
|
runtime_pop_scope(rt);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value bshell_runtime_eval(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
return runtime_eval(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_runtime_push_scope(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
struct runtime_scope *scope = runtime_push_scope(
|
||||||
|
rt,
|
||||||
|
RUNTIME_SCOPE_SCRIPT,
|
||||||
|
block);
|
||||||
|
return scope ? BSHELL_SUCCESS : BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_runtime_pop_scope(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
runtime_pop_scope(rt);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "opcode.h"
|
||||||
|
|
||||||
|
#include <fx/int.h>
|
||||||
|
|
||||||
|
#define OPCODE_MAX 0xFF
|
||||||
|
#define ARG_MAX 0xFFFFFF
|
||||||
|
|
||||||
|
bshell_instruction bshell_instruction_encode(
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg)
|
||||||
|
{
|
||||||
|
if (opcode > OPCODE_MAX) {
|
||||||
|
return BSHELL_INSTRUCTION_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx_u32_htob((opcode & OPCODE_MAX) | (arg & ARG_MAX) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_instruction_decode(
|
||||||
|
bshell_instruction instr,
|
||||||
|
enum bshell_opcode *out_opcode,
|
||||||
|
uint32_t *out_arg)
|
||||||
|
{
|
||||||
|
instr = fx_u32_btoh(instr);
|
||||||
|
*out_opcode = (instr & OPCODE_MAX);
|
||||||
|
*out_arg = ((instr >> 8) & ARG_MAX);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#ifndef RUNTIME_OPCODE_H_
|
||||||
|
#define RUNTIME_OPCODE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define BSHELL_INSTRUCTION_INVALID 0xFFFFFFFF
|
||||||
|
|
||||||
|
typedef uint32_t bshell_instruction;
|
||||||
|
|
||||||
|
enum bshell_opcode {
|
||||||
|
OPCODE_NOP = 0,
|
||||||
|
OPCODE_LDC_INT,
|
||||||
|
OPCODE_LDC_STR,
|
||||||
|
OPCODE_LDC_FP,
|
||||||
|
OPCODE_LDGLOBAL,
|
||||||
|
OPCODE_LDLOCAL,
|
||||||
|
OPCODE_LDBLOCK,
|
||||||
|
OPCODE_LDENV,
|
||||||
|
OPCODE_LDSTATIC,
|
||||||
|
OPCODE_LDARG,
|
||||||
|
OPCODE_LDPROP,
|
||||||
|
OPCODE_LDELEM,
|
||||||
|
OPCODE_LDELEM_C,
|
||||||
|
OPCODE_STLOCAL,
|
||||||
|
OPCODE_STPROP,
|
||||||
|
OPCODE_STELEM,
|
||||||
|
OPCODE_LDCMD,
|
||||||
|
OPCODE_PEXEC,
|
||||||
|
OPCODE_CALL,
|
||||||
|
OPCODE_MK_STR,
|
||||||
|
OPCODE_MK_ARRAY,
|
||||||
|
OPCODE_MK_HTAB,
|
||||||
|
OPCODE_POP,
|
||||||
|
OPCODE_ADD,
|
||||||
|
OPCODE_SUB,
|
||||||
|
OPCODE_MUL,
|
||||||
|
OPCODE_DIV,
|
||||||
|
OPCODE_ADD_IP,
|
||||||
|
OPCODE_MOD,
|
||||||
|
OPCODE_INC,
|
||||||
|
OPCODE_DEC,
|
||||||
|
OPCODE_SHL,
|
||||||
|
OPCODE_SHR,
|
||||||
|
OPCODE_BAND,
|
||||||
|
OPCODE_BOR,
|
||||||
|
OPCODE_BXOR,
|
||||||
|
OPCODE_BNOT,
|
||||||
|
OPCODE_CMP_NULL,
|
||||||
|
OPCODE_CMP_EQ,
|
||||||
|
OPCODE_CMP_NE,
|
||||||
|
OPCODE_CMP_LT,
|
||||||
|
OPCODE_CMP_GT,
|
||||||
|
OPCODE_CMP_LE,
|
||||||
|
OPCODE_CMP_GE,
|
||||||
|
OPCODE_LAND,
|
||||||
|
OPCODE_LOR,
|
||||||
|
OPCODE_LXOR,
|
||||||
|
OPCODE_LNOT,
|
||||||
|
OPCODE_BR,
|
||||||
|
OPCODE_BR_TRUE,
|
||||||
|
OPCODE_RANGE,
|
||||||
|
OPCODE_MATCH,
|
||||||
|
OPCODE_REPLACE,
|
||||||
|
OPCODE_LIKE,
|
||||||
|
OPCODE_IN,
|
||||||
|
OPCODE_FMT,
|
||||||
|
OPCODE_CONTAINS,
|
||||||
|
OPCODE_SPLIT,
|
||||||
|
OPCODE_JOIN,
|
||||||
|
OPCODE_IS,
|
||||||
|
OPCODE_AS,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern bshell_instruction bshell_instruction_encode(
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg);
|
||||||
|
extern void bshell_instruction_decode(
|
||||||
|
bshell_instruction instr,
|
||||||
|
enum bshell_opcode *out_opcode,
|
||||||
|
uint32_t *out_arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
#include "pipeline.h"
|
||||||
|
|
||||||
|
#include "../status.h"
|
||||||
|
#include "cmdcall.h"
|
||||||
|
|
||||||
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_pipeline_p {
|
||||||
|
bshell_pipeline *p_self;
|
||||||
|
fx_array *p_in, *p_out;
|
||||||
|
FX_VECTOR_DECLARE(bshell_cmdcall *, p_cmds);
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pipeline_init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_pipeline_p *pipeline = priv;
|
||||||
|
pipeline->p_self = obj;
|
||||||
|
pipeline->p_in = fx_array_create();
|
||||||
|
pipeline->p_out = fx_array_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pipeline_fini(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_pipeline_p *pipeline = priv;
|
||||||
|
for (size_t i = 0; i < pipeline->p_cmds.count; i++) {
|
||||||
|
bshell_cmdcall_unref(pipeline->p_cmds.items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline->p_in) {
|
||||||
|
fx_array_unref(pipeline->p_in);
|
||||||
|
pipeline->p_in = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeline->p_out) {
|
||||||
|
fx_array_unref(pipeline->p_out);
|
||||||
|
pipeline->p_out = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status write_value(
|
||||||
|
struct bshell_pipeline_p *pipeline,
|
||||||
|
fx_array *dest,
|
||||||
|
fx_value value,
|
||||||
|
bool enumerate)
|
||||||
|
{
|
||||||
|
if (!enumerate) {
|
||||||
|
fx_array_push_back(dest, value);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_object *container = NULL;
|
||||||
|
fx_value_get_object(&value, &container);
|
||||||
|
if (!container) {
|
||||||
|
fx_array_push_back(dest, value);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_iterator *it = fx_iterator_begin(container);
|
||||||
|
fx_foreach(v, it)
|
||||||
|
{
|
||||||
|
fx_array_push_back(dest, fx_value_copy_return(v));
|
||||||
|
}
|
||||||
|
fx_iterator_unref(it);
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status pipeline_add_input_value(
|
||||||
|
struct bshell_pipeline_p *pipeline,
|
||||||
|
fx_value value,
|
||||||
|
bool enumerate)
|
||||||
|
{
|
||||||
|
return write_value(pipeline, pipeline->p_in, value, enumerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status pipeline_add_cmdcall(
|
||||||
|
struct bshell_pipeline_p *pipeline,
|
||||||
|
bshell_cmdcall *cmdcall)
|
||||||
|
{
|
||||||
|
bshell_cmdcall **slot = fx_vector_emplace_back(pipeline->p_cmds, NULL);
|
||||||
|
*slot = bshell_cmdcall_ref(cmdcall);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status pipeline_execute_single(
|
||||||
|
struct bshell_pipeline_p *pipeline)
|
||||||
|
{
|
||||||
|
return BSHELL_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_value pipeline_read_value(struct bshell_pipeline_p *pipeline)
|
||||||
|
{
|
||||||
|
return fx_array_pop_front(pipeline->p_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status pipeline_write_value(
|
||||||
|
struct bshell_pipeline_p *pipeline,
|
||||||
|
fx_value value,
|
||||||
|
bool enumerate)
|
||||||
|
{
|
||||||
|
return write_value(pipeline, pipeline->p_out, value, enumerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status pipeline_pump_record(
|
||||||
|
struct bshell_pipeline_p *pipeline,
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
fx_value *result,
|
||||||
|
int *out_end_of_data)
|
||||||
|
{
|
||||||
|
enum bshell_status status = BSHELL_SUCCESS;
|
||||||
|
if (fx_array_get_size(pipeline->p_out)) {
|
||||||
|
fx_value out = fx_array_pop_front(pipeline->p_out);
|
||||||
|
*result = out;
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < pipeline->p_cmds.count;) {
|
||||||
|
status = bshell_cmdcall_process_record(
|
||||||
|
pipeline->p_cmds.items[i],
|
||||||
|
pipeline->p_self,
|
||||||
|
rt);
|
||||||
|
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool input_available = fx_array_get_size(pipeline->p_in) != 0;
|
||||||
|
bool output_available = fx_array_get_size(pipeline->p_out) != 0;
|
||||||
|
|
||||||
|
if (input_available) {
|
||||||
|
/* repeat this pipeline stage until all available input
|
||||||
|
* records are consumed */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!output_available) {
|
||||||
|
/* no output produced, and no more input available */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < pipeline->p_cmds.count - 1) {
|
||||||
|
fx_array *tmp = pipeline->p_in;
|
||||||
|
pipeline->p_in = pipeline->p_out;
|
||||||
|
pipeline->p_out = tmp;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fx_array_get_size(pipeline->p_out)) {
|
||||||
|
fx_value out = fx_array_pop_front(pipeline->p_out);
|
||||||
|
*result = out;
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
} else if (i == 0) {
|
||||||
|
*result = FX_VALUE_EMPTY;
|
||||||
|
*out_end_of_data = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < pipeline->p_cmds.count; i++) {
|
||||||
|
status = bshell_command_process_record(
|
||||||
|
pipeline->p_cmds.items[i],
|
||||||
|
rt);
|
||||||
|
|
||||||
|
if (status != BSHELL_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_array *tmp = pipeline->p_in;
|
||||||
|
pipeline->p_in = pipeline->p_out;
|
||||||
|
pipeline->p_out = tmp;
|
||||||
|
|
||||||
|
if (fx_array_size(pipeline->p_in)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in->v_type) {
|
||||||
|
fx_value_copy(result, in);
|
||||||
|
} else if (i == 0) {
|
||||||
|
*out_end_of_data = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_unset(in);
|
||||||
|
fx_value_unset(out);
|
||||||
|
#endif
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_pipeline_add_input_value(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
fx_value value,
|
||||||
|
bool enumerate)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_add_input_value,
|
||||||
|
pipeline,
|
||||||
|
value,
|
||||||
|
enumerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_pipeline_add_cmdcall(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
bshell_cmdcall *cmd)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_add_cmdcall,
|
||||||
|
pipeline,
|
||||||
|
cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_pipeline_execute_single(bshell_pipeline *pipeline)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_execute_single,
|
||||||
|
pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_pipeline_pump_record(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
fx_value *out,
|
||||||
|
int *out_end_of_data)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_pump_record,
|
||||||
|
pipeline,
|
||||||
|
rt,
|
||||||
|
out,
|
||||||
|
out_end_of_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value bshell_pipeline_read_value(bshell_pipeline *pipeline)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_read_value,
|
||||||
|
pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_pipeline_write_value(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
fx_value val,
|
||||||
|
bool enumerate)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_PIPELINE,
|
||||||
|
pipeline_write_value,
|
||||||
|
pipeline,
|
||||||
|
val,
|
||||||
|
enumerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_pipeline)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_CONSTRUCTOR("create", bshell_pipeline_create, 0, FX_TYPE_VOID);
|
||||||
|
FX_TYPE_CLASS_END(bshell_pipeline)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_pipeline)
|
||||||
|
FX_TYPE_ID(0x64159f21, 0xb1dd, 0x4838, 0xba62, 0x69fa65cc01d3);
|
||||||
|
FX_TYPE_NAME("bshell.pipeline");
|
||||||
|
FX_TYPE_CLASS(bshell_pipeline_class);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_pipeline_p);
|
||||||
|
FX_TYPE_INSTANCE_INIT(pipeline_init);
|
||||||
|
FX_TYPE_INSTANCE_FINI(pipeline_fini);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_pipeline)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef RUNTIME_PIPELINE_H_
|
||||||
|
#define RUNTIME_PIPELINE_H_
|
||||||
|
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../runtime/cmdcall.h"
|
||||||
|
#include "../status.h"
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_PIPELINE (bshell_pipeline_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_pipeline);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_pipeline)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_pipeline)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_pipeline_get_type(void);
|
||||||
|
|
||||||
|
FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_pipeline, BSHELL_TYPE_PIPELINE);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_pipeline_add_input_value(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
fx_value value,
|
||||||
|
bool enumerate);
|
||||||
|
extern enum bshell_status bshell_pipeline_add_cmdcall(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
bshell_cmdcall *cmd);
|
||||||
|
extern enum bshell_status bshell_pipeline_execute_single(
|
||||||
|
bshell_pipeline *pipeline);
|
||||||
|
extern enum bshell_status bshell_pipeline_pump_record(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
fx_value *out,
|
||||||
|
int *out_end_of_data);
|
||||||
|
|
||||||
|
extern fx_value bshell_pipeline_read_value(bshell_pipeline *pipeline);
|
||||||
|
extern enum bshell_status bshell_pipeline_write_value(
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
fx_value val,
|
||||||
|
bool enumerate);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct bshell_runtime *bshell_runtime_create(void)
|
||||||
|
{
|
||||||
|
struct bshell_runtime *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->rt_global = runtime_push_scope(out, RUNTIME_SCOPE_GLOBAL, NULL);
|
||||||
|
out->rt_aliases = fx_hashtable_create();
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_runtime_destroy(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
fx_hashtable_unref(rt->rt_aliases);
|
||||||
|
free(rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable *bshell_runtime_find_var(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
bshell_variable *var = NULL;
|
||||||
|
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
|
||||||
|
while (cur) {
|
||||||
|
struct runtime_scope *scope = fx_unbox(
|
||||||
|
struct runtime_scope,
|
||||||
|
cur,
|
||||||
|
s_entry);
|
||||||
|
var = var_map_get(&scope->s_vars, name);
|
||||||
|
if (var) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = fx_queue_prev(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable *bshell_runtime_define_var(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct runtime_scope *scope = runtime_get_scope(rt);
|
||||||
|
if (!scope) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable *var = bshell_variable_create(name);
|
||||||
|
if (!var) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_map_put(&scope->s_vars, var);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_command *bshell_runtime_find_command(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *callable_name)
|
||||||
|
{
|
||||||
|
bshell_command *alias = NULL, *func = NULL;
|
||||||
|
const fx_value *alias_v = fx_hashtable_get(
|
||||||
|
rt->rt_aliases,
|
||||||
|
&FX_CSTR(callable_name));
|
||||||
|
if (alias_v) {
|
||||||
|
fx_value_get_object(alias_v, &alias);
|
||||||
|
bshell_command_ref(alias);
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_queue_entry *cur = fx_queue_last(&rt->rt_scope);
|
||||||
|
while (cur) {
|
||||||
|
struct runtime_scope *scope = fx_unbox(
|
||||||
|
struct runtime_scope,
|
||||||
|
cur,
|
||||||
|
s_entry);
|
||||||
|
const fx_value *func_v = fx_hashtable_get(
|
||||||
|
scope->s_functions,
|
||||||
|
&FX_CSTR(callable_name));
|
||||||
|
if (func_v) {
|
||||||
|
fx_value_get_object(func_v, &func);
|
||||||
|
bshell_command_ref(func);
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = fx_queue_prev(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_command *cmd = bshell_command_find_static(callable_name);
|
||||||
|
if (cmd) {
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO find native executables */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef RUNTIME_RUNTIME_H_
|
||||||
|
#define RUNTIME_RUNTIME_H_
|
||||||
|
|
||||||
|
#include "../command/command.h"
|
||||||
|
#include "../script-block.h"
|
||||||
|
#include "var.h"
|
||||||
|
|
||||||
|
#include <fx/collections/hashtable.h>
|
||||||
|
#include <fx/queue.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
struct runtime_scope;
|
||||||
|
|
||||||
|
struct bshell_runtime {
|
||||||
|
struct runtime_scope *rt_global;
|
||||||
|
fx_hashtable *rt_aliases;
|
||||||
|
fx_queue rt_scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct bshell_runtime *bshell_runtime_create(void);
|
||||||
|
extern void bshell_runtime_destroy(struct bshell_runtime *rt);
|
||||||
|
|
||||||
|
extern fx_value bshell_runtime_eval_global(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block);
|
||||||
|
extern fx_value bshell_runtime_eval_script(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block);
|
||||||
|
|
||||||
|
extern bshell_variable *bshell_runtime_find_var(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *name);
|
||||||
|
extern bshell_variable *bshell_runtime_define_var(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
extern bshell_command *bshell_runtime_find_command(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
const char *callable_name);
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_runtime_push_scope(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
bshell_scriptblock *block);
|
||||||
|
extern enum bshell_status bshell_runtime_pop_scope(struct bshell_runtime *rt);
|
||||||
|
extern fx_value bshell_runtime_eval(struct bshell_runtime *rt);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#include "scope.h"
|
||||||
|
|
||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
#include <fx/vector.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct runtime_scope *runtime_push_scope(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
enum runtime_scope_type type,
|
||||||
|
bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
struct runtime_scope *out = malloc(sizeof *out);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out, 0x0, sizeof *out);
|
||||||
|
|
||||||
|
out->s_type = type;
|
||||||
|
out->s_functions = fx_hashtable_create();
|
||||||
|
|
||||||
|
if (block) {
|
||||||
|
runtime_scope_set_block(out, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_queue_push_back(&rt->rt_scope, &out->s_entry);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runtime_pop_scope(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
fx_queue_entry *entry = fx_queue_pop_back(&rt->rt_scope);
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct runtime_scope *scope = fx_unbox(
|
||||||
|
struct runtime_scope,
|
||||||
|
entry,
|
||||||
|
s_entry);
|
||||||
|
/* TODO */
|
||||||
|
fx_hashtable_unref(scope->s_functions);
|
||||||
|
free(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
fx_queue_entry *entry = fx_queue_last(&rt->rt_scope);
|
||||||
|
if (!entry) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fx_unbox(struct runtime_scope, entry, s_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runtime_scope_push_value(
|
||||||
|
struct runtime_scope *scope,
|
||||||
|
const fx_value *value)
|
||||||
|
{
|
||||||
|
fx_value *slot = fx_vector_emplace_back(scope->s_stack, NULL);
|
||||||
|
if (!slot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_copy(slot, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value runtime_scope_pop_value(struct runtime_scope *scope)
|
||||||
|
{
|
||||||
|
if (scope->s_stack.count == 0) {
|
||||||
|
return FX_VALUE_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value v = scope->s_stack.items[scope->s_stack.count - 1];
|
||||||
|
fx_vector_pop_back(scope->s_stack, NULL);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runtime_scope_set_block(
|
||||||
|
struct runtime_scope *scope,
|
||||||
|
bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
scope->s_block = block;
|
||||||
|
scope->s_ip = 0;
|
||||||
|
bshell_scriptblock_get_text(block, &scope->s_instr, &scope->s_nr_instr);
|
||||||
|
bshell_scriptblock_get_pool(block, &scope->s_pool, &scope->s_nr_pool);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef RUNTIME_SCOPE_H_
|
||||||
|
#define RUNTIME_SCOPE_H_
|
||||||
|
|
||||||
|
#include "../script-block.h"
|
||||||
|
#include "var-map.h"
|
||||||
|
|
||||||
|
#include <fx/collections/hashtable.h>
|
||||||
|
#include <fx/namemap.h>
|
||||||
|
#include <fx/queue.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
enum runtime_scope_type {
|
||||||
|
RUNTIME_SCOPE_OTHER = 0,
|
||||||
|
RUNTIME_SCOPE_SCRIPT,
|
||||||
|
RUNTIME_SCOPE_GLOBAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct runtime_scope {
|
||||||
|
enum runtime_scope_type s_type;
|
||||||
|
fx_queue_entry s_entry;
|
||||||
|
struct var_map s_vars;
|
||||||
|
fx_hashtable *s_functions;
|
||||||
|
FX_VECTOR_DECLARE(fx_value, s_stack);
|
||||||
|
size_t s_ip;
|
||||||
|
|
||||||
|
bshell_scriptblock *s_block;
|
||||||
|
bshell_instruction *s_instr;
|
||||||
|
size_t s_nr_instr;
|
||||||
|
fx_value *s_pool;
|
||||||
|
size_t s_nr_pool;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct runtime_scope *runtime_push_scope(
|
||||||
|
struct bshell_runtime *rt,
|
||||||
|
enum runtime_scope_type type,
|
||||||
|
bshell_scriptblock *block);
|
||||||
|
extern void runtime_pop_scope(struct bshell_runtime *rt);
|
||||||
|
extern struct runtime_scope *runtime_get_scope(struct bshell_runtime *rt);
|
||||||
|
|
||||||
|
extern void runtime_scope_push_value(
|
||||||
|
struct runtime_scope *scope,
|
||||||
|
const fx_value *value);
|
||||||
|
extern fx_value runtime_scope_pop_value(struct runtime_scope *scope);
|
||||||
|
|
||||||
|
extern void runtime_scope_set_block(
|
||||||
|
struct runtime_scope *scope,
|
||||||
|
bshell_scriptblock *block);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "var-map.h"
|
||||||
|
|
||||||
|
void var_map_cleanup(struct var_map *map)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status var_map_put(struct var_map *map, bshell_variable *var)
|
||||||
|
{
|
||||||
|
const char *name = bshell_variable_get_name(var);
|
||||||
|
struct var_map_entry *entry = malloc(sizeof *entry);
|
||||||
|
if (!entry) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(entry, 0x0, sizeof *entry);
|
||||||
|
|
||||||
|
entry->e_var = var;
|
||||||
|
|
||||||
|
fx_namemap_put(&map->m_vars, name, &entry->e_entry);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable *var_map_get(struct var_map *map, const char *name)
|
||||||
|
{
|
||||||
|
fx_namemap_entry *e = fx_namemap_get(&map->m_vars, name);
|
||||||
|
if (!e) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct var_map_entry *entry = fx_unbox(
|
||||||
|
struct var_map_entry,
|
||||||
|
e,
|
||||||
|
e_entry);
|
||||||
|
return entry->e_var;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef RUNTIME_VAR_MAP_H_
|
||||||
|
#define RUNTIME_VAR_MAP_H_
|
||||||
|
|
||||||
|
#include "../status.h"
|
||||||
|
#include "var.h"
|
||||||
|
|
||||||
|
struct var_map_entry {
|
||||||
|
bshell_variable *e_var;
|
||||||
|
fx_namemap_entry e_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct var_map {
|
||||||
|
fx_namemap m_vars;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void var_map_cleanup(struct var_map *map);
|
||||||
|
|
||||||
|
extern enum bshell_status var_map_put(
|
||||||
|
struct var_map *map,
|
||||||
|
bshell_variable *var);
|
||||||
|
extern bshell_variable *var_map_get(struct var_map *map, const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include "var.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_variable_p {
|
||||||
|
char *var_name;
|
||||||
|
fx_value var_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void variable_fini(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_variable_p *block = priv;
|
||||||
|
|
||||||
|
if (block->var_name) {
|
||||||
|
free(block->var_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_unset(&block->var_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *variable_get_name(struct bshell_variable_p *var)
|
||||||
|
{
|
||||||
|
return var->var_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const fx_value *variable_get_value(const struct bshell_variable_p *var)
|
||||||
|
{
|
||||||
|
return &var->var_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void variable_set_value(struct bshell_variable_p *var, fx_value *value)
|
||||||
|
{
|
||||||
|
fx_value_unset(&var->var_value);
|
||||||
|
fx_value_copy(&var->var_value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_variable *bshell_variable_create(const char *name)
|
||||||
|
{
|
||||||
|
bshell_variable *var = fx_object_create(BSHELL_TYPE_VARIABLE);
|
||||||
|
if (!var) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bshell_variable_p *p = fx_object_get_private(
|
||||||
|
var,
|
||||||
|
BSHELL_TYPE_VARIABLE);
|
||||||
|
|
||||||
|
p->var_name = fx_strdup(name);
|
||||||
|
if (!p->var_name) {
|
||||||
|
bshell_variable_unref(var);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *bshell_variable_get_name(const bshell_variable *var)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(
|
||||||
|
BSHELL_TYPE_VARIABLE,
|
||||||
|
variable_get_name,
|
||||||
|
var);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fx_value *bshell_variable_get_value(const bshell_variable *var)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(
|
||||||
|
BSHELL_TYPE_VARIABLE,
|
||||||
|
variable_get_value,
|
||||||
|
var);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_variable_set_value(bshell_variable *var, fx_value *value)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_V(
|
||||||
|
BSHELL_TYPE_VARIABLE,
|
||||||
|
variable_set_value,
|
||||||
|
var,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_variable)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_CONSTRUCTOR("create", bshell_variable_create, 1, FX_TYPE_CSTR);
|
||||||
|
FX_TYPE_CLASS_END(bshell_variable)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_variable)
|
||||||
|
FX_TYPE_ID(0x4e93b9d9, 0x2c11, 0x4fd7, 0xa9ce, 0x41b7cd20f0d4);
|
||||||
|
FX_TYPE_NAME("bshell.variable");
|
||||||
|
FX_TYPE_CLASS(bshell_variable_class);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_variable_p);
|
||||||
|
FX_TYPE_INSTANCE_FINI(variable_fini);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_variable)
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef RUNTIME_VAR_H_
|
||||||
|
#define RUNTIME_VAR_H_
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_VARIABLE (bshell_variable_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_variable);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_variable)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_variable)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_variable_get_type(void);
|
||||||
|
|
||||||
|
extern bshell_variable *bshell_variable_create(const char *name);
|
||||||
|
|
||||||
|
extern const char *bshell_variable_get_name(const bshell_variable *var);
|
||||||
|
extern const fx_value *bshell_variable_get_value(const bshell_variable *var);
|
||||||
|
extern void bshell_variable_set_value(bshell_variable *var, fx_value *value);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,355 @@
|
|||||||
|
#include "script-block.h"
|
||||||
|
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct string_cache_entry {
|
||||||
|
unsigned long e_index;
|
||||||
|
fx_namemap_entry e_entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bshell_scriptblock_p {
|
||||||
|
/* pool values referenced by the text */
|
||||||
|
FX_VECTOR_DECLARE(fx_value, b_pool);
|
||||||
|
/* bytecode instructions */
|
||||||
|
FX_VECTOR_DECLARE(bshell_instruction, b_text);
|
||||||
|
/* string value cache */
|
||||||
|
fx_namemap b_strings;
|
||||||
|
};
|
||||||
|
|
||||||
|
static fx_status pool_destroy(void *p)
|
||||||
|
{
|
||||||
|
fx_value_unset(p);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_vector_ops pool_ops = {
|
||||||
|
.v_destroy = pool_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scriptblock_fini(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_scriptblock_p *block = priv;
|
||||||
|
|
||||||
|
fx_vector_destroy(block->b_pool, &pool_ops);
|
||||||
|
fx_vector_destroy(block->b_text, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t scriptblock_push_instruction(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg)
|
||||||
|
{
|
||||||
|
size_t offset = block->b_text.count * sizeof(bshell_instruction);
|
||||||
|
uint32_t instr = bshell_instruction_encode(opcode, arg);
|
||||||
|
fx_vector_push_back(block->b_text, &instr, NULL);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status scriptblock_read_instruction(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode *out_opcode,
|
||||||
|
uint32_t *out_arg)
|
||||||
|
{
|
||||||
|
offset /= sizeof(bshell_instruction);
|
||||||
|
if (offset >= block->b_text.count) {
|
||||||
|
return BSHELL_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_opcode opcode;
|
||||||
|
uint32_t arg;
|
||||||
|
bshell_instruction_decode(block->b_text.items[offset], &opcode, &arg);
|
||||||
|
|
||||||
|
if (out_opcode) {
|
||||||
|
*out_opcode = opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_arg) {
|
||||||
|
*out_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scriptblock_patch_instruction(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg)
|
||||||
|
{
|
||||||
|
offset /= sizeof(bshell_instruction);
|
||||||
|
if (offset >= block->b_text.count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->b_text.items[offset] = bshell_instruction_encode(opcode, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scriptblock_clear_text(struct bshell_scriptblock_p *block)
|
||||||
|
{
|
||||||
|
block->b_text.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scriptblock_get_text(
|
||||||
|
const struct bshell_scriptblock_p *block,
|
||||||
|
bshell_instruction **out_ptr,
|
||||||
|
size_t *out_count)
|
||||||
|
{
|
||||||
|
if (out_ptr) {
|
||||||
|
*out_ptr = block->b_text.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_count) {
|
||||||
|
*out_count = block->b_text.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scriptblock_get_pool(
|
||||||
|
const struct bshell_scriptblock_p *block,
|
||||||
|
fx_value **out_ptr,
|
||||||
|
size_t *out_count)
|
||||||
|
{
|
||||||
|
if (out_ptr) {
|
||||||
|
*out_ptr = block->b_pool.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_count) {
|
||||||
|
*out_count = block->b_pool.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long scriptblock_add_pool_value(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
fx_value *value)
|
||||||
|
{
|
||||||
|
unsigned long id = block->b_pool.count;
|
||||||
|
fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops);
|
||||||
|
if (!slot) {
|
||||||
|
return (unsigned long)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value_copy(slot, value);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_value *scriptblock_get_pool_value(
|
||||||
|
const struct bshell_scriptblock_p *block,
|
||||||
|
unsigned long index,
|
||||||
|
fx_type_id expected_type)
|
||||||
|
{
|
||||||
|
if (index >= block->b_pool.count) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value *value = &block->b_pool.items[index];
|
||||||
|
if (expected_type
|
||||||
|
&& fx_type_id_compare(value->v_type, expected_type) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long scriptblock_get_string(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
const char *s)
|
||||||
|
{
|
||||||
|
struct string_cache_entry *cache_entry = NULL;
|
||||||
|
fx_string *str = NULL;
|
||||||
|
|
||||||
|
fx_namemap_entry *e = fx_namemap_get(&block->b_strings, s);
|
||||||
|
if (e) {
|
||||||
|
cache_entry = fx_unbox(struct string_cache_entry, e, e_entry);
|
||||||
|
return cache_entry->e_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_entry = malloc(sizeof *cache_entry);
|
||||||
|
if (!cache_entry) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = fx_string_create_from_cstr(s);
|
||||||
|
if (!str) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long index = block->b_pool.count;
|
||||||
|
fx_value *slot = fx_vector_emplace_back(block->b_pool, &pool_ops);
|
||||||
|
if (!slot) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
*slot = FX_VALUE_OBJECT(str);
|
||||||
|
|
||||||
|
cache_entry->e_index = index;
|
||||||
|
fx_namemap_put(
|
||||||
|
&block->b_strings,
|
||||||
|
fx_string_get_cstr(str),
|
||||||
|
&cache_entry->e_entry);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (str) {
|
||||||
|
fx_string_unref(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache_entry) {
|
||||||
|
free(cache_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return POOL_INDEX_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long scriptblock_get_double(
|
||||||
|
struct bshell_scriptblock_p *block,
|
||||||
|
double v)
|
||||||
|
{
|
||||||
|
fx_value value = FX_DOUBLE(v);
|
||||||
|
return scriptblock_add_pool_value(block, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bshell_scriptblock_push_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_push_instruction,
|
||||||
|
block,
|
||||||
|
opcode,
|
||||||
|
arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_status bshell_scriptblock_read_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode *out_opcode,
|
||||||
|
uint32_t *out_arg)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_read_instruction,
|
||||||
|
block,
|
||||||
|
offset,
|
||||||
|
out_opcode,
|
||||||
|
out_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_scriptblock_patch_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_V(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_patch_instruction,
|
||||||
|
block,
|
||||||
|
offset,
|
||||||
|
opcode,
|
||||||
|
arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_scriptblock_clear_text(bshell_scriptblock *block)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_V0(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_clear_text,
|
||||||
|
block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_scriptblock_get_text(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
bshell_instruction **out_ptr,
|
||||||
|
size_t *out_count)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_get_text,
|
||||||
|
block,
|
||||||
|
out_ptr,
|
||||||
|
out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bshell_scriptblock_get_pool(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
fx_value **out_ptr,
|
||||||
|
size_t *out_count)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_get_pool,
|
||||||
|
block,
|
||||||
|
out_ptr,
|
||||||
|
out_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long bshell_scriptblock_add_pool_value(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
fx_value *value)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_add_pool_value,
|
||||||
|
block,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_value *bshell_scriptblock_get_pool_value(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
unsigned long index,
|
||||||
|
fx_type_id expected_type)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_get_pool_value,
|
||||||
|
block,
|
||||||
|
index,
|
||||||
|
expected_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long bshell_scriptblock_get_string(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
const char *s)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_get_string,
|
||||||
|
block,
|
||||||
|
s);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long bshell_scriptblock_get_double(bshell_scriptblock *block, double v)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC(
|
||||||
|
BSHELL_TYPE_SCRIPTBLOCK,
|
||||||
|
scriptblock_get_double,
|
||||||
|
block,
|
||||||
|
v);
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_scriptblock)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_CONSTRUCTOR(
|
||||||
|
"create",
|
||||||
|
bshell_scriptblock_create,
|
||||||
|
0,
|
||||||
|
FX_TYPE_VOID);
|
||||||
|
FX_TYPE_CLASS_END(bshell_scriptblock)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_scriptblock)
|
||||||
|
FX_TYPE_ID(0x02b87313, 0x83f6, 0x4a57, 0xa573, 0x62cf492391ce);
|
||||||
|
FX_TYPE_NAME("bshell.scriptblock");
|
||||||
|
FX_TYPE_CLASS(bshell_scriptblock_class);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_scriptblock_p);
|
||||||
|
FX_TYPE_INSTANCE_FINI(scriptblock_fini);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_scriptblock)
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef SCRIPT_BLOCK_H_
|
||||||
|
#define SCRIPT_BLOCK_H_
|
||||||
|
|
||||||
|
#include "runtime/opcode.h"
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
#include <fx/value.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
enum bshell_opcode;
|
||||||
|
|
||||||
|
#define POOL_INDEX_INVALID ((unsigned long)-1)
|
||||||
|
#define BSHELL_TYPE_SCRIPTBLOCK (bshell_scriptblock_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_scriptblock);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_scriptblock)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_scriptblock)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_scriptblock_get_type(void);
|
||||||
|
|
||||||
|
FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_scriptblock, BSHELL_TYPE_SCRIPTBLOCK);
|
||||||
|
|
||||||
|
extern size_t bshell_scriptblock_push_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg);
|
||||||
|
extern enum bshell_status bshell_scriptblock_read_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode *out_opcode,
|
||||||
|
uint32_t *out_arg);
|
||||||
|
extern void bshell_scriptblock_patch_instruction(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
size_t offset,
|
||||||
|
enum bshell_opcode opcode,
|
||||||
|
uint32_t arg);
|
||||||
|
|
||||||
|
extern void bshell_scriptblock_clear_text(bshell_scriptblock *block);
|
||||||
|
extern void bshell_scriptblock_get_text(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
bshell_instruction **out_ptr,
|
||||||
|
size_t *out_count);
|
||||||
|
extern void bshell_scriptblock_get_pool(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
fx_value **out_ptr,
|
||||||
|
size_t *out_count);
|
||||||
|
extern unsigned long bshell_scriptblock_add_pool_value(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
fx_value *value);
|
||||||
|
extern fx_value *bshell_scriptblock_get_pool_value(
|
||||||
|
const bshell_scriptblock *block,
|
||||||
|
unsigned long index,
|
||||||
|
fx_type_id expected_type);
|
||||||
|
extern unsigned long bshell_scriptblock_get_string(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
const char *s);
|
||||||
|
extern unsigned long bshell_scriptblock_get_double(
|
||||||
|
bshell_scriptblock *block,
|
||||||
|
double v);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
+819
@@ -0,0 +1,819 @@
|
|||||||
|
#include "verb.h"
|
||||||
|
|
||||||
|
#include "status.h"
|
||||||
|
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/reflection/property.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
struct bshell_verb_p {
|
||||||
|
enum bshell_verb_id v_id;
|
||||||
|
const char *v_name;
|
||||||
|
const char *v_alias_prefix;
|
||||||
|
const char *v_group;
|
||||||
|
const char *v_description;
|
||||||
|
};
|
||||||
|
|
||||||
|
bshell_verb *bshell_verb_create(
|
||||||
|
enum bshell_verb_id id,
|
||||||
|
const char *name,
|
||||||
|
const char *alias_prefix,
|
||||||
|
const char *group,
|
||||||
|
const char *description)
|
||||||
|
{
|
||||||
|
bshell_verb *verb = fx_object_create(BSHELL_TYPE_VERB);
|
||||||
|
if (!verb) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bshell_verb_p *verb_p = fx_object_get_private(
|
||||||
|
verb,
|
||||||
|
BSHELL_TYPE_VERB);
|
||||||
|
|
||||||
|
verb_p->v_id = id;
|
||||||
|
verb_p->v_name = name;
|
||||||
|
verb_p->v_alias_prefix = alias_prefix;
|
||||||
|
verb_p->v_group = group;
|
||||||
|
verb_p->v_description = description;
|
||||||
|
|
||||||
|
return verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool verb_is_reserved(const struct bshell_verb_p *verb)
|
||||||
|
{
|
||||||
|
return !strcmp(verb->v_group, "Reserved");
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_verb_id verb_get_id(const struct bshell_verb_p *verb)
|
||||||
|
{
|
||||||
|
return verb->v_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *verb_get_name(const struct bshell_verb_p *verb)
|
||||||
|
{
|
||||||
|
return verb->v_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bshell_verb_is_reserved(const bshell_verb *verb)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(BSHELL_TYPE_VERB, verb_is_reserved, verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum bshell_verb_id bshell_verb_get_id(const bshell_verb *verb)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(BSHELL_TYPE_VERB, verb_get_id, verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *bshell_verb_get_name(const bshell_verb *verb)
|
||||||
|
{
|
||||||
|
FX_CLASS_DISPATCH_STATIC_0(BSHELL_TYPE_VERB, verb_get_name, verb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_name(
|
||||||
|
const fx_value *verb_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_verb *verb = NULL;
|
||||||
|
fx_value_get_object(verb_v, &verb);
|
||||||
|
struct bshell_verb_p *verb_p = fx_object_get_private(
|
||||||
|
verb,
|
||||||
|
BSHELL_TYPE_VERB);
|
||||||
|
|
||||||
|
*out = FX_CSTR(verb_p->v_name);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_alias_prefix(
|
||||||
|
const fx_value *verb_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_verb *verb = NULL;
|
||||||
|
fx_value_get_object(verb_v, &verb);
|
||||||
|
struct bshell_verb_p *verb_p = fx_object_get_private(
|
||||||
|
verb,
|
||||||
|
BSHELL_TYPE_VERB);
|
||||||
|
*out = FX_CSTR(verb_p->v_alias_prefix);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_group(
|
||||||
|
const fx_value *verb_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_verb *verb = NULL;
|
||||||
|
fx_value_get_object(verb_v, &verb);
|
||||||
|
struct bshell_verb_p *verb_p = fx_object_get_private(
|
||||||
|
verb,
|
||||||
|
BSHELL_TYPE_VERB);
|
||||||
|
*out = FX_CSTR(verb_p->v_group);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fx_status get_description(
|
||||||
|
const fx_value *verb_v,
|
||||||
|
const fx_property *prop,
|
||||||
|
fx_value *out)
|
||||||
|
{
|
||||||
|
bshell_verb *verb = NULL;
|
||||||
|
fx_value_get_object(verb_v, &verb);
|
||||||
|
struct bshell_verb_p *verb_p = fx_object_get_private(
|
||||||
|
verb,
|
||||||
|
BSHELL_TYPE_VERB);
|
||||||
|
*out = FX_CSTR(verb_p->v_description);
|
||||||
|
return FX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_verb)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_PROPERTY("verb", get_name, NULL);
|
||||||
|
FX_TYPE_PROPERTY("alias_prefix", get_alias_prefix, NULL);
|
||||||
|
FX_TYPE_PROPERTY("group", get_group, NULL);
|
||||||
|
FX_TYPE_PROPERTY("description", get_description, NULL);
|
||||||
|
|
||||||
|
FX_TYPE_CONSTRUCTOR("create", bshell_verb_create, 0, FX_TYPE_VOID);
|
||||||
|
FX_TYPE_CLASS_END(bshell_verb)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_verb)
|
||||||
|
FX_TYPE_ID(0x90eb98eb, 0x5497, 0x47a7, 0x923c, 0x01538c070f21);
|
||||||
|
FX_TYPE_NAME("bshell.verb");
|
||||||
|
FX_TYPE_CLASS(bshell_verb_class);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_verb_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_verb)
|
||||||
|
|
||||||
|
static fx_hashtable *all_verbs_by_name = NULL;
|
||||||
|
static bshell_verb *all_verbs_by_id[__BSHELL_VERB_MAX] = {};
|
||||||
|
|
||||||
|
#define PUT_VERB(id, name, prefix, group, desc) \
|
||||||
|
do { \
|
||||||
|
bshell_verb *verb = bshell_verb_create( \
|
||||||
|
BSHELL_VERB_##id, \
|
||||||
|
name, \
|
||||||
|
prefix, \
|
||||||
|
group, \
|
||||||
|
desc); \
|
||||||
|
if (!verb) { \
|
||||||
|
return BSHELL_ERR_NO_MEMORY; \
|
||||||
|
} \
|
||||||
|
all_verbs_by_id[BSHELL_VERB_##id] = verb; \
|
||||||
|
fx_string *name_lower = fx_string_create_from_cstr(name); \
|
||||||
|
fx_string_transform_lowercase(name_lower); \
|
||||||
|
fx_hashtable_put( \
|
||||||
|
all_verbs_by_name, \
|
||||||
|
&FX_VALUE_OBJECT(name_lower), \
|
||||||
|
&FX_VALUE_OBJECT(verb)); \
|
||||||
|
fx_string_unref(name_lower); \
|
||||||
|
bshell_verb_unref(verb); \
|
||||||
|
} while (0)
|
||||||
|
#define PUT_RESERVED_VERB(id, name, prefix) \
|
||||||
|
do { \
|
||||||
|
bshell_verb *verb = bshell_verb_create( \
|
||||||
|
BSHELL_VERB_##id, \
|
||||||
|
name, \
|
||||||
|
prefix, \
|
||||||
|
"Reserved", \
|
||||||
|
NULL); \
|
||||||
|
if (!verb) { \
|
||||||
|
return BSHELL_ERR_NO_MEMORY; \
|
||||||
|
} \
|
||||||
|
all_verbs_by_id[BSHELL_VERB_##id] = verb; \
|
||||||
|
fx_string *name_lower = fx_string_create_from_cstr(name); \
|
||||||
|
fx_string_transform_lowercase(name_lower); \
|
||||||
|
fx_hashtable_put( \
|
||||||
|
all_verbs_by_name, \
|
||||||
|
&FX_VALUE_OBJECT(name_lower), \
|
||||||
|
&FX_VALUE_OBJECT(verb)); \
|
||||||
|
fx_string_unref(name_lower); \
|
||||||
|
bshell_verb_unref(verb); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
enum bshell_status bshell_init_all_verbs(void)
|
||||||
|
{
|
||||||
|
all_verbs_by_name = fx_hashtable_create();
|
||||||
|
PUT_VERB(
|
||||||
|
ADD,
|
||||||
|
"Add",
|
||||||
|
"a",
|
||||||
|
"Common",
|
||||||
|
"Adds a resource to a container, or attaches an item to "
|
||||||
|
"another item");
|
||||||
|
PUT_VERB(
|
||||||
|
CLEAR,
|
||||||
|
"Clear",
|
||||||
|
"cl",
|
||||||
|
"Common",
|
||||||
|
"Removes all the resources from a container but does not "
|
||||||
|
"delete the container");
|
||||||
|
PUT_VERB(
|
||||||
|
CLOSE,
|
||||||
|
"Close",
|
||||||
|
"cs",
|
||||||
|
"Common",
|
||||||
|
"Changes the state of a resource to make it inaccessible, "
|
||||||
|
"unavailable, or unusable");
|
||||||
|
PUT_VERB(
|
||||||
|
COPY,
|
||||||
|
"Copy",
|
||||||
|
"cp",
|
||||||
|
"Common",
|
||||||
|
"Copies a resource to another name or to another container");
|
||||||
|
PUT_VERB(
|
||||||
|
ENTER,
|
||||||
|
"Enter",
|
||||||
|
"et",
|
||||||
|
"Common",
|
||||||
|
"Specifies an action that allows the user to move into a "
|
||||||
|
"resource");
|
||||||
|
PUT_VERB(
|
||||||
|
EXIT,
|
||||||
|
"Exit",
|
||||||
|
"ex",
|
||||||
|
"Common",
|
||||||
|
"Sets the current environment or context to the most recently "
|
||||||
|
"used context");
|
||||||
|
PUT_VERB(
|
||||||
|
FIND,
|
||||||
|
"Find",
|
||||||
|
"fd",
|
||||||
|
"Common",
|
||||||
|
"Looks for an object in a container that is unknown, implied, "
|
||||||
|
"optional, or specified");
|
||||||
|
PUT_VERB(
|
||||||
|
FORMAT,
|
||||||
|
"Format",
|
||||||
|
"f",
|
||||||
|
"Common",
|
||||||
|
"Arranges objects in a specified form or layout");
|
||||||
|
PUT_VERB(
|
||||||
|
GET,
|
||||||
|
"Get",
|
||||||
|
"g",
|
||||||
|
"Common",
|
||||||
|
"Specifies an action that retrieves a resource");
|
||||||
|
PUT_VERB(HIDE, "Hide", "h", "Common", "Makes a resource undetectable");
|
||||||
|
PUT_VERB(
|
||||||
|
JOIN,
|
||||||
|
"Join",
|
||||||
|
"j",
|
||||||
|
"Common",
|
||||||
|
"Combines resources into one resource");
|
||||||
|
PUT_VERB(LOCK, "Lock", "lk", "Common", "Secures a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
MOVE,
|
||||||
|
"Move",
|
||||||
|
"m",
|
||||||
|
"Common",
|
||||||
|
"Moves a resource from one location to another");
|
||||||
|
PUT_VERB(NEW, "New", "n", "Common", "Creates a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
OPEN,
|
||||||
|
"Open",
|
||||||
|
"op",
|
||||||
|
"Common",
|
||||||
|
"Changes the state of a resource to make it accessible, "
|
||||||
|
"available, or usable");
|
||||||
|
PUT_VERB(
|
||||||
|
OPTIMIZE,
|
||||||
|
"Optimize",
|
||||||
|
"om",
|
||||||
|
"Common",
|
||||||
|
"Increases the effectiveness of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
PUSH,
|
||||||
|
"Push",
|
||||||
|
"pu",
|
||||||
|
"Common",
|
||||||
|
"Adds an item to the top of a stack");
|
||||||
|
PUT_VERB(
|
||||||
|
POP,
|
||||||
|
"Pop",
|
||||||
|
"pop",
|
||||||
|
"Common",
|
||||||
|
"Removes an item from the top of a stack");
|
||||||
|
PUT_VERB(
|
||||||
|
REDO,
|
||||||
|
"Redo",
|
||||||
|
"re",
|
||||||
|
"Common",
|
||||||
|
"Resets a resource to the state that was undone");
|
||||||
|
PUT_VERB(
|
||||||
|
REMOVE,
|
||||||
|
"Remove",
|
||||||
|
"r",
|
||||||
|
"Common",
|
||||||
|
"Deletes a resource from a container");
|
||||||
|
PUT_VERB(
|
||||||
|
RENAME,
|
||||||
|
"Rename",
|
||||||
|
"rn",
|
||||||
|
"Common",
|
||||||
|
"Changes the name of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
RESET,
|
||||||
|
"Reset",
|
||||||
|
"rs",
|
||||||
|
"Common",
|
||||||
|
"Sets a resource back to its original state");
|
||||||
|
PUT_VERB(
|
||||||
|
RESIZE,
|
||||||
|
"Resize",
|
||||||
|
"rz",
|
||||||
|
"Common",
|
||||||
|
"Changes the size of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
SEARCH,
|
||||||
|
"Search",
|
||||||
|
"sr",
|
||||||
|
"Common",
|
||||||
|
"Creates a reference to a resource in a container");
|
||||||
|
PUT_VERB(
|
||||||
|
SELECT,
|
||||||
|
"Select",
|
||||||
|
"sc",
|
||||||
|
"Common",
|
||||||
|
"Locates a resource in a container");
|
||||||
|
PUT_VERB(
|
||||||
|
SET,
|
||||||
|
"Set",
|
||||||
|
"s",
|
||||||
|
"Common",
|
||||||
|
"Replaces data on an existing resource or creates a resource "
|
||||||
|
"that contains some data");
|
||||||
|
PUT_VERB(
|
||||||
|
SHOW,
|
||||||
|
"Show",
|
||||||
|
"sh",
|
||||||
|
"Common",
|
||||||
|
"Makes a resource visible to the user");
|
||||||
|
PUT_VERB(
|
||||||
|
SKIP,
|
||||||
|
"Skip",
|
||||||
|
"sk",
|
||||||
|
"Common",
|
||||||
|
"Bypasses one or more resources or points in a sequence");
|
||||||
|
PUT_VERB(
|
||||||
|
SPLIT,
|
||||||
|
"Split",
|
||||||
|
"sl",
|
||||||
|
"Common",
|
||||||
|
"Separates parts of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
STEP,
|
||||||
|
"Step",
|
||||||
|
"st",
|
||||||
|
"Common",
|
||||||
|
"Moves to the next point or resource in a sequence");
|
||||||
|
PUT_VERB(
|
||||||
|
SWITCH,
|
||||||
|
"Switch",
|
||||||
|
"sw",
|
||||||
|
"Common",
|
||||||
|
"Specifies an action that alternates between two resources, "
|
||||||
|
"such as to change between two locations, responsibilities, or "
|
||||||
|
"states");
|
||||||
|
PUT_VERB(
|
||||||
|
UNDO,
|
||||||
|
"Undo",
|
||||||
|
"un",
|
||||||
|
"Common",
|
||||||
|
"Sets a resource to its previous state");
|
||||||
|
PUT_VERB(
|
||||||
|
UNLOCK,
|
||||||
|
"Unlock",
|
||||||
|
"uk",
|
||||||
|
"Common",
|
||||||
|
"Releases a resource that was locked");
|
||||||
|
PUT_VERB(
|
||||||
|
WATCH,
|
||||||
|
"Watch",
|
||||||
|
"wc",
|
||||||
|
"Common",
|
||||||
|
"Continually inspects or monitors a resource for changes");
|
||||||
|
PUT_VERB(
|
||||||
|
CONNECT,
|
||||||
|
"Connect",
|
||||||
|
"cc",
|
||||||
|
"Communications",
|
||||||
|
"Creates a link between a source and a destination");
|
||||||
|
PUT_VERB(
|
||||||
|
DISCONNECT,
|
||||||
|
"Disconnect",
|
||||||
|
"dc",
|
||||||
|
"Communications",
|
||||||
|
"Breaks the link between a source and a destination");
|
||||||
|
PUT_VERB(
|
||||||
|
READ,
|
||||||
|
"Read",
|
||||||
|
"rd",
|
||||||
|
"Communications",
|
||||||
|
"Acquires information from a source");
|
||||||
|
PUT_VERB(
|
||||||
|
RECEIVE,
|
||||||
|
"Receive",
|
||||||
|
"rc",
|
||||||
|
"Communications",
|
||||||
|
"Accepts information sent from a source");
|
||||||
|
PUT_VERB(
|
||||||
|
SEND,
|
||||||
|
"Send",
|
||||||
|
"sd",
|
||||||
|
"Communications",
|
||||||
|
"Delivers information to a destination");
|
||||||
|
PUT_VERB(
|
||||||
|
WRITE,
|
||||||
|
"Write",
|
||||||
|
"wr",
|
||||||
|
"Communications",
|
||||||
|
"Adds information to a target");
|
||||||
|
PUT_VERB(
|
||||||
|
BACKUP,
|
||||||
|
"Backup",
|
||||||
|
"ba",
|
||||||
|
"Data",
|
||||||
|
"Stores data by replicating it");
|
||||||
|
PUT_VERB(
|
||||||
|
CHECKPOINT,
|
||||||
|
"Checkpoint",
|
||||||
|
"ch",
|
||||||
|
"Data",
|
||||||
|
"Creates a snapshot of the current state of the data or of its "
|
||||||
|
"configuration");
|
||||||
|
PUT_VERB(
|
||||||
|
COMPARE,
|
||||||
|
"Compare",
|
||||||
|
"cr",
|
||||||
|
"Data",
|
||||||
|
"Evaluates the data from one resource against the data from "
|
||||||
|
"another resource");
|
||||||
|
PUT_VERB(
|
||||||
|
COMPRESS,
|
||||||
|
"Compress",
|
||||||
|
"cm",
|
||||||
|
"Data",
|
||||||
|
"Compacts the data of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
CONVERT,
|
||||||
|
"Convert",
|
||||||
|
"cv",
|
||||||
|
"Data",
|
||||||
|
"Changes the data from one representation to another when the "
|
||||||
|
"cmdlet supports bidirectional conversion or when the cmdlet "
|
||||||
|
"supports conversion between multiple data types");
|
||||||
|
PUT_VERB(
|
||||||
|
CONVERTFROM,
|
||||||
|
"ConvertFrom",
|
||||||
|
"cf",
|
||||||
|
"Data",
|
||||||
|
"Converts one primary type of input (the cmdlet noun indicates "
|
||||||
|
"the input) to one or more supported output types");
|
||||||
|
PUT_VERB(
|
||||||
|
CONVERTTO,
|
||||||
|
"ConvertTo",
|
||||||
|
"ct",
|
||||||
|
"Data",
|
||||||
|
"Converts from one or more types of input to a primary output "
|
||||||
|
"type (the cmdlet noun indicates the output type)");
|
||||||
|
PUT_VERB(
|
||||||
|
DISMOUNT,
|
||||||
|
"Dismount",
|
||||||
|
"dm",
|
||||||
|
"Data",
|
||||||
|
"Detaches a named entity from a location");
|
||||||
|
PUT_VERB(
|
||||||
|
EDIT,
|
||||||
|
"Edit",
|
||||||
|
"ed",
|
||||||
|
"Data",
|
||||||
|
"Modifies existing data by adding or removing content");
|
||||||
|
PUT_VERB(
|
||||||
|
EXPAND,
|
||||||
|
"Expand",
|
||||||
|
"en",
|
||||||
|
"Data",
|
||||||
|
"Restores the data of a resource that has been compressed to "
|
||||||
|
"its original state");
|
||||||
|
PUT_VERB(
|
||||||
|
EXPORT,
|
||||||
|
"Export",
|
||||||
|
"ep",
|
||||||
|
"Data",
|
||||||
|
"Encapsulates the primary input into a persistent data store, "
|
||||||
|
"such as a file, or into an interchange format");
|
||||||
|
PUT_VERB(
|
||||||
|
GROUP,
|
||||||
|
"Group",
|
||||||
|
"gp",
|
||||||
|
"Data",
|
||||||
|
"Arranges or associates one or more resources");
|
||||||
|
PUT_VERB(
|
||||||
|
IMPORT,
|
||||||
|
"Import",
|
||||||
|
"ip",
|
||||||
|
"Data",
|
||||||
|
"Creates a resource from data that is stored in a persistent "
|
||||||
|
"data store (such as a file) or in an interchange format");
|
||||||
|
PUT_VERB(
|
||||||
|
INITIALIZE,
|
||||||
|
"Initialize",
|
||||||
|
"in",
|
||||||
|
"Data",
|
||||||
|
"Prepares a resource for use, and sets it to a default state");
|
||||||
|
PUT_VERB(
|
||||||
|
LIMIT,
|
||||||
|
"Limit",
|
||||||
|
"l",
|
||||||
|
"Data",
|
||||||
|
"Applies constraints to a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
MERGE,
|
||||||
|
"Merge",
|
||||||
|
"mg",
|
||||||
|
"Data",
|
||||||
|
"Creates a single resource from multiple resources");
|
||||||
|
PUT_VERB(
|
||||||
|
MOUNT,
|
||||||
|
"Mount",
|
||||||
|
"mt",
|
||||||
|
"Data",
|
||||||
|
"Attaches a named entity to a location");
|
||||||
|
PUT_VERB(OUT, "Out", "o", "Data", "Sends data out of the environment");
|
||||||
|
PUT_VERB(
|
||||||
|
PUBLISH,
|
||||||
|
"Publish",
|
||||||
|
"pb",
|
||||||
|
"Data",
|
||||||
|
"Makes a resource available to others");
|
||||||
|
PUT_VERB(
|
||||||
|
RESTORE,
|
||||||
|
"Restore",
|
||||||
|
"rr",
|
||||||
|
"Data",
|
||||||
|
"Sets a resource to a predefined state, such as a state set by "
|
||||||
|
"Checkpoint");
|
||||||
|
PUT_VERB(SAVE, "Save", "sv", "Data", "Preserves data to avoid loss");
|
||||||
|
PUT_VERB(
|
||||||
|
SYNC,
|
||||||
|
"Sync",
|
||||||
|
"sy",
|
||||||
|
"Data",
|
||||||
|
"Assures that two or more resources are in the same state");
|
||||||
|
PUT_VERB(
|
||||||
|
UNPUBLISH,
|
||||||
|
"Unpublish",
|
||||||
|
"ub",
|
||||||
|
"Data",
|
||||||
|
"Makes a resource unavailable to others");
|
||||||
|
PUT_VERB(
|
||||||
|
UPDATE,
|
||||||
|
"Update",
|
||||||
|
"ud",
|
||||||
|
"Data",
|
||||||
|
"Brings a resource up-to-date to maintain its state, accuracy, "
|
||||||
|
"conformance, or compliance");
|
||||||
|
PUT_VERB(
|
||||||
|
DEBUG,
|
||||||
|
"Debug",
|
||||||
|
"db",
|
||||||
|
"Diagnostic",
|
||||||
|
"Examines a resource to diagnose operational problems");
|
||||||
|
PUT_VERB(
|
||||||
|
MEASURE,
|
||||||
|
"Measure",
|
||||||
|
"ms",
|
||||||
|
"Diagnostic",
|
||||||
|
"Identifies resources that are consumed by a specified "
|
||||||
|
"operation, or retrieves statistics about a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
REPAIR,
|
||||||
|
"Repair",
|
||||||
|
"rp",
|
||||||
|
"Diagnostic",
|
||||||
|
"Restores a resource to a usable condition");
|
||||||
|
PUT_VERB(
|
||||||
|
RESOLVE,
|
||||||
|
"Resolve",
|
||||||
|
"rv",
|
||||||
|
"Diagnostic",
|
||||||
|
"Maps a shorthand representation of a resource to a more "
|
||||||
|
"complete representation");
|
||||||
|
PUT_VERB(
|
||||||
|
TEST,
|
||||||
|
"Test",
|
||||||
|
"t",
|
||||||
|
"Diagnostic",
|
||||||
|
"Verifies the operation or consistency of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
TRACE,
|
||||||
|
"Trace",
|
||||||
|
"tr",
|
||||||
|
"Diagnostic",
|
||||||
|
"Tracks the activities of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
APPROVE,
|
||||||
|
"Approve",
|
||||||
|
"ap",
|
||||||
|
"Lifecycle",
|
||||||
|
"Confirms or agrees to the status of a resource or process");
|
||||||
|
PUT_VERB(
|
||||||
|
ASSERT,
|
||||||
|
"Assert",
|
||||||
|
"as",
|
||||||
|
"Lifecycle",
|
||||||
|
"Affirms the state of a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
BUILD,
|
||||||
|
"Build",
|
||||||
|
"bd",
|
||||||
|
"Lifecycle",
|
||||||
|
"Creates an artifact (usually a binary or document) out of "
|
||||||
|
"some set of input files (usually source code or declarative "
|
||||||
|
"documents)");
|
||||||
|
PUT_VERB(
|
||||||
|
COMPLETE,
|
||||||
|
"Complete",
|
||||||
|
"cmp",
|
||||||
|
"Lifecycle",
|
||||||
|
"Concludes an operation");
|
||||||
|
PUT_VERB(
|
||||||
|
CONFIRM,
|
||||||
|
"Confirm",
|
||||||
|
"cn",
|
||||||
|
"Lifecycle",
|
||||||
|
"Acknowledges, verifies, or validates the state of a resource "
|
||||||
|
"or process");
|
||||||
|
PUT_VERB(
|
||||||
|
DENY,
|
||||||
|
"Deny",
|
||||||
|
"dn",
|
||||||
|
"Lifecycle",
|
||||||
|
"Refuses, objects, blocks, or opposes the state of a resource "
|
||||||
|
"or process");
|
||||||
|
PUT_VERB(
|
||||||
|
DEPLOY,
|
||||||
|
"Deploy",
|
||||||
|
"dp",
|
||||||
|
"Lifecycle",
|
||||||
|
"Sends an application, website, or solution to a remote "
|
||||||
|
"target[s] in such a way that a consumer of that solution can "
|
||||||
|
"access it after deployment is complete");
|
||||||
|
PUT_VERB(
|
||||||
|
DISABLE,
|
||||||
|
"Disable",
|
||||||
|
"d",
|
||||||
|
"Lifecycle",
|
||||||
|
"Configures a resource to an unavailable or inactive state");
|
||||||
|
PUT_VERB(
|
||||||
|
ENABLE,
|
||||||
|
"Enable",
|
||||||
|
"e",
|
||||||
|
"Lifecycle",
|
||||||
|
"Configures a resource to an available or active state");
|
||||||
|
PUT_VERB(
|
||||||
|
INSTALL,
|
||||||
|
"Install",
|
||||||
|
"is",
|
||||||
|
"Lifecycle",
|
||||||
|
"Places a resource in a location, and optionally initializes "
|
||||||
|
"it");
|
||||||
|
PUT_VERB(
|
||||||
|
INVOKE,
|
||||||
|
"Invoke",
|
||||||
|
"i",
|
||||||
|
"Lifecycle",
|
||||||
|
"Performs an action, such as running a command or a method");
|
||||||
|
PUT_VERB(
|
||||||
|
REGISTER,
|
||||||
|
"Register",
|
||||||
|
"rg",
|
||||||
|
"Lifecycle",
|
||||||
|
"Creates an entry for a resource in a repository such as a "
|
||||||
|
"database");
|
||||||
|
PUT_VERB(
|
||||||
|
REQUEST,
|
||||||
|
"Request",
|
||||||
|
"rq",
|
||||||
|
"Lifecycle",
|
||||||
|
"Asks for a resource or asks for permissions");
|
||||||
|
PUT_VERB(
|
||||||
|
RESTART,
|
||||||
|
"Restart",
|
||||||
|
"rt",
|
||||||
|
"Lifecycle",
|
||||||
|
"Stops an operation and then starts it again");
|
||||||
|
PUT_VERB(
|
||||||
|
RESUME,
|
||||||
|
"Resume",
|
||||||
|
"ru",
|
||||||
|
"Lifecycle",
|
||||||
|
"Starts an operation that has been suspended");
|
||||||
|
PUT_VERB(START, "Start", "sa", "Lifecycle", "Initiates an operation");
|
||||||
|
PUT_VERB(STOP, "Stop", "sp", "Lifecycle", "Discontinues an activity");
|
||||||
|
PUT_VERB(
|
||||||
|
SUBMIT,
|
||||||
|
"Submit",
|
||||||
|
"sb",
|
||||||
|
"Lifecycle",
|
||||||
|
"Presents a resource for approval");
|
||||||
|
PUT_VERB(SUSPEND, "Suspend", "ss", "Lifecycle", "Pauses an activity");
|
||||||
|
PUT_VERB(
|
||||||
|
UNINSTALL,
|
||||||
|
"Uninstall",
|
||||||
|
"us",
|
||||||
|
"Lifecycle",
|
||||||
|
"Removes a resource from an indicated location");
|
||||||
|
PUT_VERB(
|
||||||
|
UNREGISTER,
|
||||||
|
"Unregister",
|
||||||
|
"ur",
|
||||||
|
"Lifecycle",
|
||||||
|
"Removes the entry for a resource from a repository");
|
||||||
|
PUT_VERB(
|
||||||
|
WAIT,
|
||||||
|
"Wait",
|
||||||
|
"w",
|
||||||
|
"Lifecycle",
|
||||||
|
"Pauses an operation until a specified event occurs");
|
||||||
|
PUT_VERB(
|
||||||
|
USE,
|
||||||
|
"Use",
|
||||||
|
"u",
|
||||||
|
"Other",
|
||||||
|
"Uses or includes a resource to do something");
|
||||||
|
PUT_VERB(
|
||||||
|
BLOCK,
|
||||||
|
"Block",
|
||||||
|
"bl",
|
||||||
|
"Security",
|
||||||
|
"Restricts access to a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
GRANT,
|
||||||
|
"Grant",
|
||||||
|
"gr",
|
||||||
|
"Security",
|
||||||
|
"Allows access to a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
PROTECT,
|
||||||
|
"Protect",
|
||||||
|
"pt",
|
||||||
|
"Security",
|
||||||
|
"Safeguards a resource from attack or loss");
|
||||||
|
PUT_VERB(
|
||||||
|
REVOKE,
|
||||||
|
"Revoke",
|
||||||
|
"rk",
|
||||||
|
"Security",
|
||||||
|
"Specifies an action that does not allow access to a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
UNBLOCK,
|
||||||
|
"Unblock",
|
||||||
|
"ul",
|
||||||
|
"Security",
|
||||||
|
"Removes restrictions to a resource");
|
||||||
|
PUT_VERB(
|
||||||
|
UNPROTECT,
|
||||||
|
"Unprotect",
|
||||||
|
"up",
|
||||||
|
"Security",
|
||||||
|
"Removes safeguards from a resource that were added to prevent "
|
||||||
|
"it from attack or loss");
|
||||||
|
PUT_RESERVED_VERB(FOREACH, "ForEach", "foreach");
|
||||||
|
PUT_RESERVED_VERB(PING, "Ping", "pi");
|
||||||
|
PUT_RESERVED_VERB(SORT, "Sort", "sr");
|
||||||
|
PUT_RESERVED_VERB(TEE, "Tee", "te");
|
||||||
|
PUT_RESERVED_VERB(WHERE, "Where", "wh");
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_hashtable *bshell_get_all_verbs(void)
|
||||||
|
{
|
||||||
|
return all_verbs_by_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_verb *bshell_verb_get_by_id(enum bshell_verb_id id)
|
||||||
|
{
|
||||||
|
if (id >= __BSHELL_VERB_MAX) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_verbs_by_id[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_verb *bshell_verb_get_by_name(const char *name)
|
||||||
|
{
|
||||||
|
const fx_value *val = fx_hashtable_get(
|
||||||
|
all_verbs_by_name,
|
||||||
|
&FX_CSTR(name));
|
||||||
|
if (!val) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_verb *result = NULL;
|
||||||
|
fx_value_get_object(val, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
#ifndef VERB_H_
|
||||||
|
#define VERB_H_
|
||||||
|
|
||||||
|
#include <fx/collections/hashtable.h>
|
||||||
|
#include <fx/macros.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_VERB (bshell_verb_get_type())
|
||||||
|
|
||||||
|
enum bshell_verb_id {
|
||||||
|
BSHELL_VERB_NONE = 0,
|
||||||
|
BSHELL_VERB_ADD,
|
||||||
|
BSHELL_VERB_CLEAR,
|
||||||
|
BSHELL_VERB_CLOSE,
|
||||||
|
BSHELL_VERB_COPY,
|
||||||
|
BSHELL_VERB_ENTER,
|
||||||
|
BSHELL_VERB_EXIT,
|
||||||
|
BSHELL_VERB_FIND,
|
||||||
|
BSHELL_VERB_FORMAT,
|
||||||
|
BSHELL_VERB_GET,
|
||||||
|
BSHELL_VERB_HIDE,
|
||||||
|
BSHELL_VERB_JOIN,
|
||||||
|
BSHELL_VERB_LOCK,
|
||||||
|
BSHELL_VERB_MOVE,
|
||||||
|
BSHELL_VERB_NEW,
|
||||||
|
BSHELL_VERB_OPEN,
|
||||||
|
BSHELL_VERB_OPTIMIZE,
|
||||||
|
BSHELL_VERB_PUSH,
|
||||||
|
BSHELL_VERB_POP,
|
||||||
|
BSHELL_VERB_REDO,
|
||||||
|
BSHELL_VERB_REMOVE,
|
||||||
|
BSHELL_VERB_RENAME,
|
||||||
|
BSHELL_VERB_RESET,
|
||||||
|
BSHELL_VERB_RESIZE,
|
||||||
|
BSHELL_VERB_SEARCH,
|
||||||
|
BSHELL_VERB_SELECT,
|
||||||
|
BSHELL_VERB_SET,
|
||||||
|
BSHELL_VERB_SHOW,
|
||||||
|
BSHELL_VERB_SKIP,
|
||||||
|
BSHELL_VERB_SPLIT,
|
||||||
|
BSHELL_VERB_STEP,
|
||||||
|
BSHELL_VERB_SWITCH,
|
||||||
|
BSHELL_VERB_UNDO,
|
||||||
|
BSHELL_VERB_UNLOCK,
|
||||||
|
BSHELL_VERB_WATCH,
|
||||||
|
BSHELL_VERB_CONNECT,
|
||||||
|
BSHELL_VERB_DISCONNECT,
|
||||||
|
BSHELL_VERB_READ,
|
||||||
|
BSHELL_VERB_RECEIVE,
|
||||||
|
BSHELL_VERB_SEND,
|
||||||
|
BSHELL_VERB_WRITE,
|
||||||
|
BSHELL_VERB_BACKUP,
|
||||||
|
BSHELL_VERB_CHECKPOINT,
|
||||||
|
BSHELL_VERB_COMPARE,
|
||||||
|
BSHELL_VERB_COMPRESS,
|
||||||
|
BSHELL_VERB_CONVERT,
|
||||||
|
BSHELL_VERB_CONVERTFROM,
|
||||||
|
BSHELL_VERB_CONVERTTO,
|
||||||
|
BSHELL_VERB_DISMOUNT,
|
||||||
|
BSHELL_VERB_EDIT,
|
||||||
|
BSHELL_VERB_EXPAND,
|
||||||
|
BSHELL_VERB_EXPORT,
|
||||||
|
BSHELL_VERB_GROUP,
|
||||||
|
BSHELL_VERB_IMPORT,
|
||||||
|
BSHELL_VERB_INITIALIZE,
|
||||||
|
BSHELL_VERB_LIMIT,
|
||||||
|
BSHELL_VERB_MERGE,
|
||||||
|
BSHELL_VERB_MOUNT,
|
||||||
|
BSHELL_VERB_OUT,
|
||||||
|
BSHELL_VERB_PUBLISH,
|
||||||
|
BSHELL_VERB_RESTORE,
|
||||||
|
BSHELL_VERB_SAVE,
|
||||||
|
BSHELL_VERB_SYNC,
|
||||||
|
BSHELL_VERB_UNPUBLISH,
|
||||||
|
BSHELL_VERB_UPDATE,
|
||||||
|
BSHELL_VERB_DEBUG,
|
||||||
|
BSHELL_VERB_MEASURE,
|
||||||
|
BSHELL_VERB_REPAIR,
|
||||||
|
BSHELL_VERB_RESOLVE,
|
||||||
|
BSHELL_VERB_TEST,
|
||||||
|
BSHELL_VERB_TRACE,
|
||||||
|
BSHELL_VERB_APPROVE,
|
||||||
|
BSHELL_VERB_ASSERT,
|
||||||
|
BSHELL_VERB_BUILD,
|
||||||
|
BSHELL_VERB_COMPLETE,
|
||||||
|
BSHELL_VERB_CONFIRM,
|
||||||
|
BSHELL_VERB_DENY,
|
||||||
|
BSHELL_VERB_DEPLOY,
|
||||||
|
BSHELL_VERB_DISABLE,
|
||||||
|
BSHELL_VERB_ENABLE,
|
||||||
|
BSHELL_VERB_INSTALL,
|
||||||
|
BSHELL_VERB_INVOKE,
|
||||||
|
BSHELL_VERB_REGISTER,
|
||||||
|
BSHELL_VERB_REQUEST,
|
||||||
|
BSHELL_VERB_RESTART,
|
||||||
|
BSHELL_VERB_RESUME,
|
||||||
|
BSHELL_VERB_START,
|
||||||
|
BSHELL_VERB_STOP,
|
||||||
|
BSHELL_VERB_SUBMIT,
|
||||||
|
BSHELL_VERB_SUSPEND,
|
||||||
|
BSHELL_VERB_UNINSTALL,
|
||||||
|
BSHELL_VERB_UNREGISTER,
|
||||||
|
BSHELL_VERB_WAIT,
|
||||||
|
BSHELL_VERB_USE,
|
||||||
|
BSHELL_VERB_BLOCK,
|
||||||
|
BSHELL_VERB_GRANT,
|
||||||
|
BSHELL_VERB_PROTECT,
|
||||||
|
BSHELL_VERB_REVOKE,
|
||||||
|
BSHELL_VERB_UNBLOCK,
|
||||||
|
BSHELL_VERB_UNPROTECT,
|
||||||
|
/* reserved verbs */
|
||||||
|
BSHELL_VERB_FOREACH,
|
||||||
|
BSHELL_VERB_PING,
|
||||||
|
BSHELL_VERB_SORT,
|
||||||
|
BSHELL_VERB_TEE,
|
||||||
|
BSHELL_VERB_WHERE,
|
||||||
|
__BSHELL_VERB_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_verb);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_verb)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_verb)
|
||||||
|
|
||||||
|
extern enum bshell_status bshell_init_all_verbs(void);
|
||||||
|
extern fx_hashtable *bshell_get_all_verbs(void);
|
||||||
|
extern bshell_verb *bshell_verb_get_by_id(enum bshell_verb_id id);
|
||||||
|
extern bshell_verb *bshell_verb_get_by_name(const char *name);
|
||||||
|
|
||||||
|
extern fx_type_id bshell_verb_get_type(void);
|
||||||
|
|
||||||
|
extern bshell_verb *bshell_verb_create(
|
||||||
|
enum bshell_verb_id id,
|
||||||
|
const char *name,
|
||||||
|
const char *alias_prefix,
|
||||||
|
const char *group,
|
||||||
|
const char *description);
|
||||||
|
|
||||||
|
extern bool bshell_verb_is_reserved(const bshell_verb *verb);
|
||||||
|
extern enum bshell_verb_id bshell_verb_get_id(const bshell_verb *verb);
|
||||||
|
extern const char *bshell_verb_get_name(const bshell_verb *verb);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Get-Verb | %{ echo "Item: $($_.verb)" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
if ($x -gt 5) {
|
||||||
|
echo hi
|
||||||
|
} elseif ($x -lt 10) {
|
||||||
|
echo bye
|
||||||
|
} else {
|
||||||
|
echo none
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
echo hello 2> error.txt | ls -la | echo done; exit -1
|
echo hello$name 2> error.txt | ls -la | echo done; exit -1
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
echo 1 2 3 | %{ echo "Item: $_" }
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
func test-function($name) {
|
func test-function($name) {
|
||||||
|
if (5 -lt $var) {
|
||||||
|
echo good
|
||||||
|
} else {
|
||||||
|
echo bad
|
||||||
|
}
|
||||||
|
|
||||||
echo "Hello, $name! $(2 + 4 + 2) wow"
|
echo "Hello, $name! $(2 + 4 + 2) wow"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,4 +17,6 @@ $hash = @{
|
|||||||
'three' = 3
|
'three' = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hash2 = @{ 1 = 'one'; 2 = 'two'; 'three' = 3 }
|
||||||
|
|
||||||
test-function -name $obj
|
test-function -name $obj
|
||||||
|
|||||||
+14
-11
@@ -31,12 +31,12 @@ $a$b
|
|||||||
# VAR(a)
|
# VAR(a)
|
||||||
# VAR(b)
|
# VAR(b)
|
||||||
|
|
||||||
# When the parser encounters SYMBOL(%) it should switch the lexer to COMMAND
|
# When the parser encounters SYMBOL(&) it should switch the lexer to COMMAND
|
||||||
# mode, which will allow the following word construction to be used.
|
# mode, which will allow the following word construction to be used.
|
||||||
# this executes the command whose name is equal to concatenating the values
|
# this executes the command whose name is equal to concatenating the values
|
||||||
# of $a and $b (in this case, '24')
|
# of $a and $b (in this case, '24')
|
||||||
% $a$b
|
& $a$b
|
||||||
# SYMBOL(%)
|
# SYMBOL(&)
|
||||||
# WORD_START
|
# WORD_START
|
||||||
# VAR(a)
|
# VAR(a)
|
||||||
# VAR(b)
|
# VAR(b)
|
||||||
@@ -51,7 +51,7 @@ a+2b
|
|||||||
# the first char encountered is a symbol, which is read as a word in COMMAND
|
# the first char encountered is a symbol, which is read as a word in COMMAND
|
||||||
# mode
|
# mode
|
||||||
-no$a
|
-no$a
|
||||||
# WORD(-no)
|
# WORD(-no$a)
|
||||||
|
|
||||||
# returns the result of applying the NOT operator to the value of $a.
|
# returns the result of applying the NOT operator to the value of $a.
|
||||||
# the first char encountered is a symbol, which is read as a word in COMMAND
|
# the first char encountered is a symbol, which is read as a word in COMMAND
|
||||||
@@ -62,16 +62,19 @@ a+2b
|
|||||||
# OP(not)
|
# OP(not)
|
||||||
# VAR(a)
|
# VAR(a)
|
||||||
|
|
||||||
# executes the command with the name '-not$a' ($a is NOT substituted)
|
# executes the command with the name '-not$a' ($a is substituted)
|
||||||
# because of the preceding hyphen, variable substitution is not performed.
|
# because of the preceding hyphen, variable substitution is not performed.
|
||||||
% -not$a
|
& -not$a
|
||||||
# SYMBOL(%)
|
# SYMBOL(&)
|
||||||
# WORD(-not$a)
|
# WORD_START
|
||||||
|
# WORD(-not)
|
||||||
|
# VAR(a)
|
||||||
|
# WORD_END
|
||||||
|
|
||||||
# executes the command with the name '-not2' ($a IS substituted)
|
# executes the command with the name "-not$a" ($a IS substituted)
|
||||||
# variable substitution IS performed in dquote strings regardless of the hyphen.
|
# variable substitution IS performed in dquote strings regardless of the hyphen.
|
||||||
% "-not$a"
|
& "-not$a"
|
||||||
# SYMBOL(%)
|
# SYMBOL(&)
|
||||||
# STR_START
|
# STR_START
|
||||||
# STRING(-not)
|
# STRING(-not)
|
||||||
# VAR(a)
|
# VAR(a)
|
||||||
|
|||||||
Reference in New Issue
Block a user