Compare commits

..

33 Commits

Author SHA1 Message Date
wash d333497a03 meta: add clang-format config 2026-05-24 20:26:49 +01:00
wash 28f8c8f71c doc: sample: add/update sample source files 2026-05-24 20:26:40 +01:00
wash bb09e8b8d1 vim: add operator symbols and keywords 2026-05-24 20:26:29 +01:00
wash 446ee99306 build: add new sub-directories 2026-05-24 20:25:51 +01:00
wash 070a2be969 bshell: initialise verbs and table formatter on start 2026-05-24 20:25:36 +01:00
wash 862028f5a8 debug: update runtime opcode printing 2026-05-24 20:24:44 +01:00
wash d7443d7810 bshell: add an assembly instance to register builtin commands 2026-05-24 20:22:48 +01:00
wash f772f4ba20 alias: implement a set of builtin aliases 2026-05-24 20:22:30 +01:00
wash 0ee1a3575d cmdlet: implement a set of builtin cmdlets 2026-05-24 20:22:19 +01:00
wash 92e58ec7c6 runtime: implement opcodes to run commands and load/store variables and properties 2026-05-24 20:22:05 +01:00
wash 8f7a0b9fb8 runtime: add a class to represent variables and a data structure to store them 2026-05-24 20:21:39 +01:00
wash b6aeb8d4bf runtime: implement pipelines and an interface for calling commands 2026-05-24 20:21:06 +01:00
wash d8c694a43e command: add a hierarchy of classes to represent different types of commands 2026-05-24 20:20:06 +01:00
wash 4f65e3b9f2 format: implement tabular output of fx objects 2026-05-24 20:19:32 +01:00
wash c9cf6b229e bshell: add a class to manage cmdlet verbs 2026-05-24 20:18:12 +01:00
wash c3bf6dcee6 compile: implement compilation of doubles and arrays 2026-05-24 20:17:35 +01:00
wash e679c41725 compile: fstring: fix string elements being loaded at the wrong time 2026-05-24 20:17:13 +01:00
wash 30bfce5701 script-block: implement storing double values in constpool 2026-05-24 20:15:30 +01:00
wash e829c77297 file: update fx_array usage 2026-05-24 20:14:51 +01:00
wash ca8533334b ast: implement to_string for int and double nodes 2026-05-24 20:14:32 +01:00
wash fad13b5476 parse: lots of improvements 2026-05-24 20:13:55 +01:00
wash 82a035f5cc line-ed: update fx_array usage 2026-05-24 20:11:51 +01:00
wash 5a23da4cfe line-ed: add unicode support 2026-05-17 16:50:48 +01:00
wash 2f200e8d1b bshell: generate and evaluate bytecode for shell input 2026-05-17 15:35:22 +01:00
wash f629b05672 debug: implement printers for bytecode instructions and runtime values 2026-05-17 15:34:53 +01:00
wash 58b4bb2c51 runtime: temporary implementation of arithmetic bytecode evaluation 2026-05-17 15:34:24 +01:00
wash 0e8dc9cb6f bshell: implement bytecode generation for arithmetic expressions and if-statements 2026-05-17 15:33:48 +01:00
wash 2cee984092 runtime: add definitions for bshell vm bytecode 2026-05-17 15:33:20 +01:00
wash 1f8b9ff0d3 ast: implement post-order ast traversal 2026-05-17 15:32:19 +01:00
wash e490754625 bshell: add script-block class
bshell_scriptblock acts as a self-contained collection of executable bytecode and associated const value table.
2026-05-17 15:30:20 +01:00
wash 405686f6ec parse: make multi-line structure parsing more robust 2026-05-17 15:29:59 +01:00
wash d78f80a121 parse: lex: fix some state transition edge cases 2026-05-17 15:29:14 +01:00
wash 05dcf1f8b6 operator: add script-block pseudo-operator 2026-05-17 15:28:29 +01:00
96 changed files with 7207 additions and 334 deletions
+60
View File
@@ -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
View File
@@ -3,6 +3,10 @@ project(bshell C)
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(FX REQUIRED COMPONENTS
fx.runtime
@@ -14,14 +18,33 @@ execute_process(
${CMAKE_CURRENT_SOURCE_DIR}/tools/build-id.py
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/*.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}")
add_executable(bshell ${bshell_sources})
target_link_libraries(bshell FX::Runtime FX::Collections FX::Term)
target_compile_definitions(bshell PUBLIC
BSHELL_VERSION="${bshell_version}")
BSHELL_VERSION="${bshell_version}"
BSHELL_INTERACTIVE=${bshell_interactive})
+29 -5
View File
@@ -7,9 +7,11 @@ set cpoptions&vim
setlocal iskeyword+=-
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 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 match bshellLineComment /#.*$/ contains=bshellTodo
@@ -33,16 +35,33 @@ syn case match
syn cluster bshellNumber contains=bshellInteger,bshellReal
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 keyword bshellKeywordOp is not understands and or
syn match bshellBraces "[{}]" display
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 bshellArgFlag Tag
hi def link bshellVariable Identifier
hi def link bshellLineComment Comment
hi def link bshellFunctionRef Function
hi def link bshellBuiltinCommand Function
hi def link bshellString String
hi def link bshellInterpolatedString String
hi def link bshellLiteralString String
@@ -50,8 +69,13 @@ hi def link bshellInteger Number
hi def link bshellReal Float
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 bshellKeywordOp Operator
hi def link bshellTerminator Delimiter
" The default highlighting.
" hi def link bshellUnspecifiedStatement Statement
+45
View File
@@ -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)
+45
View File
@@ -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)
+24
View File
@@ -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
View File
@@ -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 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_INT] = &int_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_OP] = &op_ast_node,
};
static const size_t nr_ast_node_definitions
= sizeof ast_node_defintions / sizeof ast_node_defintions[0];
static const size_t nr_ast_node_definitions = sizeof ast_node_definitions
/ sizeof ast_node_definitions[0];
struct ast_node *ast_node_create(enum ast_node_type type)
{
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);
if (!out) {
return NULL;
@@ -80,8 +80,8 @@ void ast_node_destroy(struct ast_node *node)
break;
}
const struct ast_node_definition *def
= ast_node_defintions[node->n_type];
const struct ast_node_definition *def = ast_node_definitions
[node->n_type];
if (def->def_cleanup) {
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)
{
const struct ast_node_definition *def
= ast_node_defintions[node->n_type];
const struct ast_node_definition *def = ast_node_definitions
[node->n_type];
if (def->def_to_string) {
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);
const struct ast_node_definition *def
= ast_node_defintions[node->n_type];
const struct ast_node_definition *def = ast_node_definitions
[node->n_type];
it->it_insert_after = cur;
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);
if (cur) {
struct ast_node *cur_node
= fx_unbox(struct ast_node, cur, n_it.e_entry);
struct ast_node *cur_node = fx_unbox(
struct ast_node,
cur,
n_it.e_entry);
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 = &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
View File
@@ -8,6 +8,12 @@
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 {
AST_NONE = 0x00u,
AST_NULL,
@@ -170,6 +176,27 @@ struct ast_iterator {
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 {
enum ast_node_type def_id;
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 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 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);
+10
View File
@@ -1,6 +1,16 @@
#include "../parse/token.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 = {
.def_id = AST_DOUBLE,
.def_node_size = sizeof(struct double_ast_node),
.def_to_string = to_string,
};
+3 -1
View File
@@ -1,10 +1,12 @@
#include "../parse/token.h"
#include "ast.h"
#include <fx/stream.h>
static void to_string(const struct ast_node *node, fx_bstr *out)
{
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 = {
+102
View File
@@ -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)
+9
View File
@@ -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;
}
+143
View File
@@ -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)
+114
View File
@@ -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)
+144
View File
@@ -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)
+133
View File
@@ -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)
+35
View File
@@ -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
+60
View File
@@ -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)
+25
View File
@@ -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
+272
View File
@@ -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)
+62
View File
@@ -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
View File
+23
View File
@@ -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
+12
View File
@@ -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
+24
View File
@@ -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);
}
+61
View File
@@ -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;
}
+72
View File
@@ -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);
}
+187
View File
@@ -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
+43
View File
@@ -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;
}
+108
View File
@@ -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);
}
+72
View File
@@ -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;
}
+39
View File
@@ -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);
}
+39
View File
@@ -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);
}
+75
View File
@@ -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;
}
+67
View File
@@ -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;
}
+25
View File
@@ -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,
};
+123
View File
@@ -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);
}
+132
View File
@@ -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);
}
+66
View File
@@ -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);
}
+50
View File
@@ -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
View File
@@ -2,6 +2,8 @@
#include "ast/ast.h"
#include "parse/token.h"
#include "runtime/opcode.h"
#include "script-block.h"
#include <fx/string.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));
break;
case TOK_INT:
printf("(%lld)", tok->tok_int);
break;
case TOK_DOUBLE:
printf("(%lf)", tok->tok_double);
printf("(");
fx_value_to_string(&tok->tok_number, fx_stdout, NULL);
printf(")");
break;
default:
break;
@@ -82,15 +84,6 @@ extern void print_lex_token(struct lex_token *tok)
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++) {
fx_puts(" ");
}
@@ -143,7 +136,329 @@ void print_ast_node(struct ast_node *node)
}
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);
}
}
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");
}
+11
View File
@@ -1,6 +1,9 @@
#ifndef DEBUG_H_
#define DEBUG_H_
#include "runtime/opcode.h"
#include "script-block.h"
#include <stdbool.h>
struct ast_node;
@@ -8,5 +11,13 @@ struct lex_token;
extern void print_lex_token(struct lex_token *tok);
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
+4 -2
View File
@@ -27,13 +27,15 @@ static enum bshell_status get_row(
size_t *nr_read)
{
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) {
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);
size_t line_len = fx_string_get_size(line, FX_STRLEN_NORMAL);
+14
View File
@@ -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],
};
+29
View File
@@ -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;
}
+78
View File
@@ -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
+12
View File
@@ -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],
};
+353
View File
@@ -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;
}
+14
View File
@@ -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],
};
+9 -6
View File
@@ -1,12 +1,15 @@
#include "buffer.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++) {
line += strcspn(line, "\n");
line += fx_wstrcspn(line, L"\n");
if (*line == '\n') {
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)
{
const char *line = ed->l_buf;
const fx_wchar *line = ed->l_buf;
for (size_t i = 0; i < y; i++) {
line += strcspn(line, "\n");
line += fx_wstrcspn(line, L"\n");
if (*line == '\n') {
line++;
}
@@ -31,7 +34,7 @@ size_t line_length(struct line_ed *ed, size_t y)
return 0;
}
size_t len = strcspn(line, "\n");
size_t len = fx_wstrcspn(line, L"\n");
if (line[len] == '\n') {
len++;
}
+2 -1
View File
@@ -1,13 +1,14 @@
#ifndef LINE_ED_BUFFER_H_
#define LINE_ED_BUFFER_H_
#include <fx/encoding.h>
#include <stddef.h>
struct line_ed;
/* returns a pointer to the start of the line based on the given `y`
* 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.
* for any line other than the last line in the buffer, this length
* INCLUDES the trailing linefeed. */
+33 -18
View File
@@ -6,42 +6,55 @@
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,
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) {
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)
{
fx_string *cur
= (fx_string *)fx_array_get(ed->l_history, ed->l_history_pos);
fx_string_replace_all(cur, ed->l_buf);
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
fx_string *cur = NULL;
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)
{
fx_string *cur
= (fx_string *)fx_array_get(ed->l_history, ed->l_history_pos);
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
fx_string *cur = NULL;
fx_value_get_object(cur_v, &cur);
char s[] = {'\n', 0};
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)
{
fx_string *cur
= (fx_string *)fx_array_at(ed->l_history, ed->l_history_pos);
size_t len
= MIN((size_t)(ed->l_buf_end - ed->l_buf - 1),
fx_string_get_size(cur, FX_STRLEN_NORMAL));
fx_value *cur_v = fx_array_get_ref(ed->l_history, ed->l_history_pos);
fx_string *cur = NULL;
fx_value_get_object(cur_v, &cur);
size_t len = MIN(
(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';
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)
{
size_t nlines = fx_array_size(ed->l_history);
size_t nlines = fx_array_get_size(ed->l_history);
if (nlines < 2) {
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);
}
+36 -22
View File
@@ -8,7 +8,7 @@
#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) {
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;
char *dest = ed->l_buf_ptr;
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
fx_wchar *dest = ed->l_buf_ptr;
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
if (dest < ed->l_line_end) {
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;
char *dest = ed->l_buf_ptr;
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
fx_wchar *dest = ed->l_buf_ptr;
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
memmove(dest - 1, dest, len);
ed->l_cursor_x--;
@@ -78,8 +78,8 @@ static void backspace_nl(struct line_ed *ed)
.r_prev_line_len = prev_line_len,
};
char *dest = ed->l_buf_ptr;
size_t len = ed->l_line_end - ed->l_buf_ptr + 1;
fx_wchar *dest = ed->l_buf_ptr;
size_t len = (ed->l_line_end - ed->l_buf_ptr + 1) * sizeof *dest;
memmove(dest - 1, dest, len);
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)
{
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);
fflush(stdout);
ed->l_cursor_x--;
@@ -120,7 +120,8 @@ void cursor_left(struct line_ed *ed)
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;
}
@@ -134,9 +135,12 @@ void cursor_left(struct line_ed *ed)
size_t len = line_length(ed, ed->l_cursor_y);
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_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);
}
@@ -150,7 +154,7 @@ void cursor_right(struct line_ed *ed)
if (*ed->l_buf_ptr != '\n') {
ed->l_cursor_x++;
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);
fflush(stdout);
return;
@@ -164,7 +168,7 @@ void cursor_right(struct line_ed *ed)
ed->l_cursor_x = 0;
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_x(ed->l_tty, FX_TTY_POS_START, 0);
fflush(stdout);
@@ -177,13 +181,18 @@ void arrow_up(struct line_ed *ed)
}
if (ed->l_cursor_y > 0) {
//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);
// 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);
}
//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(
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);
save_buf_to_history(ed);
@@ -196,18 +205,23 @@ void arrow_up(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;
}
if (ed->l_cursor_y > 0) {
//printf("\033[%uA", ed->l_cursor_y);
fx_tty_move_cursor_y(ed->l_tty, FX_TTY_POS_CURSOR, (int)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);
}
//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(
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);
ed->l_history_pos++;
+3 -1
View File
@@ -1,9 +1,11 @@
#ifndef LINE_ED_INPUT_H_
#define LINE_ED_INPUT_H_
#include <fx/encoding.h>
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 cursor_left(struct line_ed *ed);
extern void cursor_right(struct line_ed *ed);
+16 -15
View File
@@ -7,6 +7,7 @@
#include <ctype.h>
#include <fx/term/tty.h>
#include <fx/wstr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -98,13 +99,13 @@ static void clear_buffer(struct line_ed *ed)
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;
size_t len = strlen(s);
fx_wchar *end = s + max;
size_t len = fx_wstrlen(s);
while (1) {
size_t r = strcspn(s, "\\");
size_t r = fx_wstrcspn(s, L"\\");
if (s + r > end) {
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;
size_t len = strlen(s);
fx_wchar *end = s + max;
size_t len = fx_wstrlen(s);
while (1) {
size_t r = strcspn(s, "\\");
size_t r = fx_wstrcspn(s, L"\\");
if (s + r > end) {
break;
}
@@ -156,9 +157,9 @@ static void remove_continuation_feeds(char *s, size_t max)
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) {
if (!isspace(*p)) {
if (!fx_wchar_is_space(*p)) {
return false;
}
}
@@ -188,7 +189,7 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
fputc('\r', stdout);
}
fputc(ed->l_buf[i], stdout);
fx_stream_write_char(fx_stdout, ed->l_buf[i]);
}
fflush(stdout);
@@ -257,7 +258,7 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
arrow_down(ed);
break;
default:
if (iswgraph(key) || key == ' ') {
if (fx_wchar_is_graph(key) || key == ' ') {
put_char(ed, key);
}
break;
@@ -275,10 +276,10 @@ size_t line_ed_readline(struct line_ed *ed, fx_stringstream *out)
ed->l_history_pos = append_to_index;
append_buf_to_history(ed);
} 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);
if (!last || strcmp(last, ed->l_buf) != 0) {
if (!last || fx_wastrcmp(last, ed->l_buf) != 0) {
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);
}
fx_stream_write_cstr(out, ed->l_buf, NULL);
fx_stream_write_wstr(out, ed->l_buf, NULL);
fx_stream_write_char(out, '\n');
return sz;
+2 -2
View File
@@ -49,9 +49,9 @@ struct line_ed {
/* input buffer, pointer to the buffer cell that corresponds to
* the current cursor position, and pointer to the byte AFTER the last
* 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 */
char *l_line_end;
fx_wchar *l_line_end;
/* 2-dimensional coordinates of the current cursor position.
* this does NOT include any prompts that are visible on the terminal */
size_t l_cursor_x, l_cursor_y;
+13 -12
View File
@@ -5,6 +5,7 @@
#include "line-ed.h"
#include <fx/term/tty.h>
#include <fx/wstr.h>
#include <stdio.h>
#include <stdlib.h>
@@ -15,19 +16,19 @@
* the (x, y) coordinates provided should be the data coordinates of the
* 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;
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)
{
const char *line_buf = ed->l_buf;
size_t line_len = strcspn(line_buf, "\n");
const fx_wchar *line_buf = ed->l_buf;
size_t line_len = fx_wstrcspn(line_buf, L"\n");
unsigned int y = 0;
@@ -44,7 +45,7 @@ void print_buffer(struct line_ed *ed)
}
y++;
line_len = strcspn(line_buf, "\n");
line_len = fx_wstrcspn(line_buf, L"\n");
fputc('\r', 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)
{
/* get the data for the line that is being refreshed */
const char *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = strcspn(line_buf, "\n");
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = fx_wstrcspn(line_buf, L"\n");
/* the index of the first char in line_buf that needs to be reprinted */
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.
* relative to where the cursor was before the linefeed was deleted,
* this is the PREVIOUS line. */
const char *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = strcspn(line_buf, "\n");
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = fx_wstrcspn(line_buf, L"\n");
/* 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.
@@ -188,7 +189,7 @@ void backspace_nl_refresh(struct line_ed *ed, struct refresh_state *state)
line_buf + start_x);
line_buf += line_len + 1;
line_len = strcspn(line_buf, "\n");
line_len = fx_wstrcspn(line_buf, L"\n");
start_x = 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)
{
/* get the data for the line that is being refreshed */
const char *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = strcspn(line_buf, "\n");
const fx_wchar *line_buf = line_start(ed, ed->l_cursor_y);
size_t line_len = fx_wstrcspn(line_buf, L"\n");
/* the index of the first char in line_buf that needs to be reprinted */
size_t start_x = ed->l_cursor_x;
+6 -1
View File
@@ -1,6 +1,7 @@
#ifndef LINE_ED_REFRESH_H_
#define LINE_ED_REFRESH_H_
#include <fx/encoding.h>
#include <stddef.h>
struct line_ed;
@@ -15,7 +16,11 @@ struct refresh_state {
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 put_refresh(struct line_ed *ed, struct refresh_state *state);
extern void backspace_nl_refresh(
+89 -9
View File
@@ -1,37 +1,117 @@
#include "ast/ast.h"
#include "compile.h"
#include "debug.h"
#include "file.h"
#include "format/format.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>
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)
{
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;
enum bshell_status status = BSHELL_SUCCESS;
if (argc > 1) {
struct file *file = NULL;
status = file_open(argv[1], &file);
linesrc = &file->f_base;
} else {
struct line_ed *ed = line_ed_create();
#if BSHELL_INTERACTIVE == 1
ed = line_ed_create();
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) {
enum bshell_status status
= line_source_readline(linesrc, linebuf);
if (status != BSHELL_SUCCESS) {
struct ast_node *node = parse_ctx_read_node(&parse);
if (!node) {
break;
}
printf("%s", fx_stringstream_ptr(linebuf));
fx_stringstream_reset(linebuf);
print_ast_node_recursive(node);
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;
+14 -10
View File
@@ -18,10 +18,6 @@
/* clang-format off */
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(CONDITIONAL_ACCESS, MEMBER_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(RIGHT_SHIFT, BITWISE, LEFT, INFIX, BINARY),
OP(ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(ADD_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(SUBTRACT_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(MULTIPLY_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(DIVIDE_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(MODULO_ASSIGN, ASSIGN, LEFT, INFIX, BINARY),
OP(ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(ADD_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(SUBTRACT_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(MULTIPLY_ASSIGN, ASSIGN, RIGHT, INFIX, BINARY),
OP(DIVIDE_ASSIGN, ASSIGN, RIGHT, 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];
+1
View File
@@ -104,6 +104,7 @@ enum operator_id {
OP_CAST,
OP_SUBEXPR,
OP_PAREN,
OP_SCRIPTBLOCK,
OP_ARRAY_START,
OP_HASHTABLE_START,
};
+7 -7
View File
@@ -19,18 +19,19 @@ static enum bshell_status arithmetic_hyphen(struct lex_ctx *ctx)
}
unsigned int token_type = TOK_WORD;
if (convert_word_to_int(tok)) {
token_type = TOK_INT;
if (convert_word_to_number(tok)) {
token_type = tok->tok_type;
/* because of APPEND_HYPHEN (which is needed to ensure operator
* tokens are detected properly), the resulting number will be
* negative.
* this token will be preceded by a HYPHEN token, so the number
* 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);
} else if (convert_word_to_operator(ctx, tok)) {
token_type = TOK_OPERATOR;
token_type = tok->tok_operator;
}
enqueue_token(ctx, tok);
@@ -108,8 +109,8 @@ static enum bshell_status arithmetic_word(struct lex_ctx *ctx)
bool kw = false, number = false;
if (convert_word_to_keyword(word)) {
token_type = word->tok_keyword;
} else if (convert_word_to_int(word)) {
token_type = TOK_INT;
} else if (convert_word_to_number(word)) {
token_type = word->tok_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[] = {
LINK_CHANGE(TOK_WORD, LEX_STATE_COMMAND),
LINK_CHANGE(SYM_EQUAL, LEX_STATE_STATEMENT),
LINK_PUSH(SYM_DQUOTE, LEX_STATE_STRING, 0),
LINK_PUSH(SYM_DOLLAR_LEFT_PAREN, LEX_STATE_STATEMENT, 0),
+5 -4
View File
@@ -19,14 +19,15 @@ static enum bshell_status hashtable_hyphen(struct lex_ctx *ctx)
}
unsigned int token_type = TOK_WORD;
if (convert_word_to_int(tok)) {
token_type = TOK_INT;
if (convert_word_to_number(tok)) {
token_type = tok->tok_type;
/* because of APPEND_HYPHEN (which is needed to ensure operator
* tokens are detected properly), the resulting number will be
* negative.
* this token will be preceded by a HYPHEN token, so the number
* 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);
} else if (convert_word_to_operator(ctx, tok)) {
token_type = tok->tok_operator;
@@ -102,7 +103,7 @@ static enum bshell_status hashtable_word(struct lex_ctx *ctx)
return status;
}
convert_word_to_int(word);
convert_word_to_number(word);
handle_lex_state_transition(ctx, word->tok_type);
enqueue_token(ctx, word);
+5 -2
View File
@@ -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_noread(struct lex_ctx *ctx);
extern bool string_is_valid_number(const char *s, long long *out);
extern bool convert_word_to_int(struct lex_token *tok);
extern bool string_is_valid_number(
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_operator(
struct lex_ctx *ctx,
+93 -34
View File
@@ -273,8 +273,10 @@ static struct lex_symbol_node *get_symbol_node(
{
fx_queue_entry *entry = fx_queue_first(&node->s_children);
while (entry) {
struct lex_symbol_node *child
= fx_unbox(struct lex_symbol_node, entry, s_entry);
struct lex_symbol_node *child = fx_unbox(
struct lex_symbol_node,
entry,
s_entry);
if (child->s_char == c) {
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);
while (entry) {
struct lex_symbol_node *node
= fx_unbox(struct lex_symbol_node, entry, s_entry);
struct lex_symbol_node *node = fx_unbox(
struct lex_symbol_node,
entry,
s_entry);
fx_queue_entry *next = fx_queue_next(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;
}
bool string_is_valid_number(const char *s, long long *out)
static bool string_could_be_double(const char *s)
{
if (s[0] == '\0') {
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);
if (strchr(s, '.')) {
return true;
}
size_t multiplier = get_int_multiplier_by_suffix(ep);
if (multiplier != 0) {
out && (*out = value * multiplier);
if (strchr(s, 'e') || strchr(s, 'E')) {
return true;
}
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)) {
return false;
}
const char *s = tok->tok_str;
long long value = 0;
if (!string_is_valid_number(s, &value)) {
fx_value value;
enum token_type type;
if (!string_is_valid_number(s, &value, &type)) {
return false;
}
lex_token_change_type(tok, TOK_INT);
tok->tok_int = value;
lex_token_change_type(tok, type);
tok->tok_number = value;
return true;
}
@@ -736,8 +784,9 @@ enum bshell_status read_var(
return ctx->lex_status;
}
struct lex_token *tok
= lex_token_create_with_string(type, fx_string_get_cstr(tmp));
struct lex_token *tok = lex_token_create_with_string(
type,
fx_string_get_cstr(tmp));
*out = tok;
return BSHELL_SUCCESS;
@@ -776,8 +825,9 @@ enum bshell_status read_braced_var(
return ctx->lex_status;
}
struct lex_token *tok
= lex_token_create_with_string(type, fx_string_get_cstr(tmp));
struct lex_token *tok = lex_token_create_with_string(
type,
fx_string_get_cstr(tmp));
*out = tok;
return BSHELL_SUCCESS;
@@ -867,13 +917,15 @@ enum bshell_status read_word(
break;
}
if (char_can_begin_symbol(ctx, c)) {
done = true;
break;
const char *s = fx_string_get_cstr(tmp);
if (number_recog && string_is_valid_number(s, NULL, NULL)) {
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(
ctx,
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)) {
op = get_operator_with_string(ctx, s);
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);
while (cur) {
struct lex_token *tok
= fx_unbox(struct lex_token, cur, tok_entry);
struct lex_token *tok = fx_unbox(
struct lex_token,
cur,
tok_entry);
if (tok->tok_type == TOK_LINEFEED) {
break;
}
+27 -9
View File
@@ -20,18 +20,19 @@ static enum bshell_status statement_hyphen(struct lex_ctx *ctx)
unsigned int token_type = TOK_WORD;
if (convert_word_to_int(tok)) {
token_type = TOK_INT;
if (convert_word_to_number(tok)) {
token_type = tok->tok_type;
/* because of APPEND_HYPHEN (which is needed to ensure operator
* tokens are detected properly), the resulting number will be
* negative.
* this token will be preceded by a HYPHEN token, so the number
* 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);
} else if (convert_word_to_operator(ctx, tok)) {
token_type = TOK_OPERATOR;
token_type = tok->tok_operator;
}
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)) {
token = word->tok_keyword;
} else if (convert_word_to_int(word)) {
token = TOK_INT;
} else if (convert_word_to_number(word)) {
token = word->tok_type;
}
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),
/* arithmetic tokens */
LINK_CHANGE(TOK_KEYWORD, LEX_STATE_ARITHMETIC),
LINK_CHANGE(SYM_SQUOTE, 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_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_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_CHANGE(SYM_LEFT_PAREN, LEX_STATE_ARITHMETIC),
LINK_CHANGE(SYM_LEFT_BRACKET, LEX_STATE_ARITHMETIC),
LINK_CHANGE(SYM_BANG, LEX_STATE_ARITHMETIC),
LINK_PUSH_WITH_TERM(
SYM_LEFT_PAREN,
@@ -178,7 +191,11 @@ static const struct lex_state_link links[] = {
SYM_RIGHT_PAREN),
/* 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(
SYM_DOLLAR_LEFT_PAREN,
LEX_STATE_STATEMENT,
@@ -213,6 +230,7 @@ static const unsigned int symbols[] = {
SYM_DQUOTE,
SYM_HASH,
SYM_AT,
SYM_AT_LEFT_PAREN,
SYM_AT_LEFT_BRACE,
SYM_PIPE,
SYM_COMMA,
+77 -53
View File
@@ -47,8 +47,10 @@ static bool finalise_expr(
break;
}
struct op_ast_node *node
= fx_unbox(struct op_ast_node, entry, n_base.n_entry);
struct op_ast_node *node = fx_unbox(
struct op_ast_node,
entry,
n_base.n_entry);
if (!node) {
/* this should never happen */
return false;
@@ -72,8 +74,10 @@ static bool finalise_expr(
int i = 0;
while (entry) {
struct ast_node *item
= fx_unbox(struct ast_node, entry, n_entry);
struct ast_node *item = fx_unbox(
struct ast_node,
entry,
n_entry);
fx_queue_entry *next = fx_queue_next(entry);
fx_queue_delete(&ctx->expr_out_queue, entry);
@@ -115,12 +119,14 @@ static bool finalise_expr(
if (op->op_arity == OPA_BINARY) {
tmp = fx_queue_pop_back(&q);
op_node->n_left
= fx_unbox(struct ast_node, tmp, n_entry);
op_node->n_left = fx_unbox(
struct ast_node,
tmp,
n_entry);
if (op_node->n_left) {
op_node->n_left->n_parent
= (struct ast_node *)op_node;
op_node->n_left->n_parent = (struct ast_node *)
op_node;
#if 0
ast_node_extend_bounds_recursive(
@@ -248,8 +254,8 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out)
parse_linefeed(ctx);
struct hashtable_ast_node *table
= (struct hashtable_ast_node *)ast_node_create(AST_HASHTABLE);
struct hashtable_ast_node *table = (struct hashtable_ast_node *)
ast_node_create(AST_HASHTABLE);
if (!table) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
return false;
@@ -264,14 +270,14 @@ static bool parse_hashtable(struct parse_ctx *ctx, struct ast_node **out)
parse_linefeed(ctx);
struct hashtable_item_ast_node *item
= (struct hashtable_item_ast_node *)ast_node_create(
AST_HASHTABLE_ITEM);
struct hashtable_item_ast_node *item = (struct
hashtable_item_ast_node
*)
ast_node_create(AST_HASHTABLE_ITEM);
struct lex_token *tok = NULL;
if (parse_word(ctx, &tok)) {
struct string_ast_node *v
= (struct string_ast_node *)ast_node_create(
AST_STRING);
struct string_ast_node *v = (struct string_ast_node *)
ast_node_create(AST_STRING);
v->n_value = tok;
item->n_key = (struct ast_node *)v;
} 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;
}
struct array_ast_node *array
= (struct array_ast_node *)ast_node_create(AST_ARRAY);
struct array_ast_node *array = (struct array_ast_node *)ast_node_create(
AST_ARRAY);
if (!array) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
return false;
@@ -377,8 +383,8 @@ bool parse_fstring(struct parse_ctx *ctx, struct ast_node **out)
discard_token(ctx);
struct fstring_ast_node *fstring
= (struct fstring_ast_node *)ast_node_create(AST_FSTRING);
struct fstring_ast_node *fstring = (struct fstring_ast_node *)
ast_node_create(AST_FSTRING);
if (!fstring) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
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);
switch (tok->tok_type) {
case TOK_INT: {
struct int_ast_node *v
= (struct int_ast_node *)ast_node_create(AST_INT);
struct int_ast_node *v = (struct int_ast_node *)ast_node_create(
AST_INT);
v->n_value = claim_token(ctx);
*out = (struct ast_node *)v;
return true;
}
case TOK_DOUBLE: {
struct double_ast_node *v
= (struct double_ast_node *)ast_node_create(AST_DOUBLE);
struct double_ast_node *v = (struct double_ast_node *)
ast_node_create(AST_DOUBLE);
v->n_value = claim_token(ctx);
*out = (struct ast_node *)v;
return true;
}
case TOK_STRING: {
struct string_ast_node *v
= (struct string_ast_node *)ast_node_create(AST_STRING);
struct string_ast_node *v = (struct string_ast_node *)
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);
*out = (struct ast_node *)v;
return true;
}
case TOK_VAR: {
struct var_ast_node *v
= (struct var_ast_node *)ast_node_create(AST_VAR);
struct var_ast_node *v = (struct var_ast_node *)ast_node_create(
AST_VAR);
v->n_ident = claim_token(ctx);
*out = (struct ast_node *)v;
return true;
@@ -492,20 +505,22 @@ void arith_push_operator(struct expr_parse_ctx *state, struct op_ast_node *node)
}
while (true) {
fx_queue_entry *top
= fx_queue_last(&state->expr_operator_stack);
fx_queue_entry *top = fx_queue_last(
&state->expr_operator_stack);
if (!top) {
break;
}
struct ast_node *top_node
= fx_unbox(struct ast_node, top, n_entry);
struct ast_node *top_node = fx_unbox(
struct ast_node,
top,
n_entry);
const struct operator_info *top_op = NULL;
switch (top_node->n_type) {
case AST_OP: {
struct op_ast_node *op_node
= (struct op_ast_node *)top_node;
struct op_ast_node *op_node = (struct op_ast_node *)
top_node;
top_op = op_node->n_op;
break;
}
@@ -575,8 +590,8 @@ static bool parse_unary_operator(
expr->expr_prev = EXPR_C_BINARY_OP;
struct op_ast_node *op_node
= (struct op_ast_node *)ast_node_create(AST_OP);
struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create(
AST_OP);
if (!op_node) {
return false;
}
@@ -639,8 +654,8 @@ static bool parse_binary_operator(
expr->expr_prev = EXPR_C_BINARY_OP;
struct op_ast_node *op_node
= (struct op_ast_node *)ast_node_create(AST_OP);
struct op_ast_node *op_node = (struct op_ast_node *)ast_node_create(
AST_OP);
if (!op_node) {
return false;
}
@@ -669,8 +684,8 @@ static bool parse_comma(struct parse_ctx *ctx, struct expr_parse_ctx *expr)
return false;
}
struct array_ast_node *array
= (struct array_ast_node *)ast_node_create(AST_ARRAY);
struct array_ast_node *array = (struct array_ast_node *)ast_node_create(
AST_ARRAY);
if (!array) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
ast_node_destroy(item);
@@ -706,8 +721,10 @@ static void dump_expr_ctx(struct expr_parse_ctx *expr)
printf("op stack:\n");
fx_queue_entry *entry = fx_queue_first(&expr->expr_operator_stack);
while (entry) {
struct ast_node *node
= fx_unbox(struct ast_node, entry, n_entry);
struct ast_node *node = fx_unbox(
struct ast_node,
entry,
n_entry);
print_ast_node(node);
entry = fx_queue_next(entry);
}
@@ -715,8 +732,10 @@ static void dump_expr_ctx(struct expr_parse_ctx *expr)
printf("out queue:\n");
entry = fx_queue_first(&expr->expr_out_queue);
while (entry) {
struct ast_node *node
= fx_unbox(struct ast_node, entry, n_entry);
struct ast_node *node = fx_unbox(
struct ast_node,
entry,
n_entry);
print_ast_node(node);
entry = fx_queue_next(entry);
}
@@ -755,17 +774,16 @@ bool parse_arith_expr(
switch (tok->tok_type) {
case TOK_LINEFEED:
expr.expr_prev_symbol = tok->tok_type;
expr.expr_done = true;
break;
case TOK_WORD: {
if (!can_use_command(&expr)) {
report_error(
ctx,
"expected a value expression");
expr.expr_fail = true;
expr.expr_fail = !parse_operand(ctx, &expr);
break;
}
expr.expr_prev_symbol = tok->tok_type;
struct ast_node *value = NULL;
if (!parse_command(ctx, &value)) {
expr.expr_fail = true;
@@ -783,10 +801,12 @@ bool parse_arith_expr(
case TOK_DOUBLE:
case TOK_STRING:
case TOK_STR_START:
expr.expr_prev_symbol = tok->tok_type;
expr.expr_fail = !parse_operand(ctx, &expr);
expr.expr_prev_symbol = tok->tok_type;
break;
case TOK_OPERATOR:
expr.expr_prev_symbol = tok->tok_operator;
switch (tok->tok_operator) {
/* these two are special cases, as they are both
* unary AND binary operators */
@@ -805,17 +825,21 @@ bool parse_arith_expr(
break;
case TKOP_BNOT:
case TKOP_NOT:
expr.expr_fail
= !parse_unary_operator(ctx, &expr);
expr.expr_fail = !parse_unary_operator(
ctx,
&expr);
break;
default:
expr.expr_fail
= !parse_binary_operator(ctx, &expr);
expr.expr_fail = !parse_binary_operator(
ctx,
&expr);
break;
}
expr.expr_prev_symbol = tok->tok_operator;
break;
case TOK_SYMBOL:
expr.expr_prev_symbol = tok->tok_symbol;
switch (tok->tok_symbol) {
case SYM_SEMICOLON:
case SYM_AMPERSAND:
@@ -848,6 +872,7 @@ bool parse_arith_expr(
case SYM_DOLLAR_LEFT_PAREN:
case SYM_AT_LEFT_PAREN:
case SYM_AT_LEFT_BRACE:
case SYM_LEFT_BRACE:
expr.expr_fail = !parse_operand(ctx, &expr);
break;
default: {
@@ -867,7 +892,6 @@ bool parse_arith_expr(
}
}
expr.expr_prev_symbol = tok->tok_symbol;
break;
default:
report_error(
+26 -5
View File
@@ -6,23 +6,44 @@ bool parse_block(struct parse_ctx *ctx, struct ast_node **out)
return false;
}
parse_linefeed(ctx);
struct block_ast_node *block
= (struct block_ast_node *)ast_node_create(AST_BLOCK);
bool ok = true;
while (1) {
if (parse_symbol(ctx, SYM_RIGHT_BRACE)) {
break;
}
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)) {
break;
}
struct ast_node *stmt = NULL;
if (!parse_statement(ctx, &stmt)) {
ast_node_destroy((struct ast_node *)block);
return false;
if (!parse_linefeed(ctx) && !parse_symbol(ctx, SYM_SEMICOLON)) {
report_error(
ctx,
"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;
-16
View File
@@ -155,19 +155,3 @@ bool parse_var(struct parse_ctx *ctx, struct lex_token **out)
*out = claim_token(ctx);
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;
}
+19 -4
View File
@@ -5,8 +5,8 @@ static bool add_branch(
struct ast_node *cond,
struct ast_node *body)
{
struct if_branch_ast_node *branch
= (struct if_branch_ast_node *)ast_node_create(AST_IF_BRANCH);
struct if_branch_ast_node *branch = (struct if_branch_ast_node *)
ast_node_create(AST_IF_BRANCH);
if (!branch) {
return false;
}
@@ -47,8 +47,8 @@ bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
return false;
}
struct if_ast_node *if_group
= (struct if_ast_node *)ast_node_create(AST_IF);
struct if_ast_node *if_group = (struct if_ast_node *)ast_node_create(
AST_IF);
if (!if_group) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
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)) {
done = true;
} 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)) {
report_error(
ctx,
@@ -77,6 +84,14 @@ bool parse_if(struct parse_ctx *ctx, struct ast_node **out)
ast_node_destroy((struct ast_node *)if_group);
return false;
}
if (!parse_symbol(ctx, SYM_RIGHT_PAREN)) {
report_error(
ctx,
"expected `)` after elseif-condition");
ast_node_destroy(if_cond);
return false;
}
} else {
done = true;
break;
+2 -2
View File
@@ -2,6 +2,7 @@
#define IVY_LANG_LEX_H_
#include <fx/queue.h>
#include <fx/value.h>
#include <stdbool.h>
struct char_cell {
@@ -129,8 +130,7 @@ struct lex_token {
enum token_keyword tok_keyword;
enum token_symbol tok_symbol;
enum token_operator tok_operator;
long long tok_int;
double tok_double;
fx_value tok_number;
char *tok_str;
};
};
+328
View File
@@ -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)
+36
View File
@@ -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
+459
View File
@@ -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;
}
+27
View File
@@ -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);
}
+82
View File
@@ -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
+277
View File
@@ -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)
+49
View File
@@ -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
+108
View File
@@ -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;
}
+47
View File
@@ -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
+89
View File
@@ -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);
}
+51
View File
@@ -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
+35
View File
@@ -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;
}
+23
View File
@@ -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
+98
View File
@@ -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)
+26
View File
@@ -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
+355
View File
@@ -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)
+65
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
Get-Verb | %{ echo "Item: $($_.verb)" }
+7
View File
@@ -0,0 +1,7 @@
if ($x -gt 5) {
echo hi
} elseif ($x -lt 10) {
echo bye
} else {
echo none
}
+1 -1
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
echo 1 2 3 | %{ echo "Item: $_" }
+8
View File
@@ -1,4 +1,10 @@
func test-function($name) {
if (5 -lt $var) {
echo good
} else {
echo bad
}
echo "Hello, $name! $(2 + 4 + 2) wow"
}
@@ -11,4 +17,6 @@ $hash = @{
'three' = 3
}
$hash2 = @{ 1 = 'one'; 2 = 'two'; 'three' = 3 }
test-function -name $obj
+14 -11
View File
@@ -31,12 +31,12 @@ $a$b
# VAR(a)
# 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.
# this executes the command whose name is equal to concatenating the values
# of $a and $b (in this case, '24')
% $a$b
# SYMBOL(%)
& $a$b
# SYMBOL(&)
# WORD_START
# VAR(a)
# VAR(b)
@@ -51,7 +51,7 @@ a+2b
# the first char encountered is a symbol, which is read as a word in COMMAND
# mode
-no$a
# WORD(-no)
# WORD(-no$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
@@ -62,16 +62,19 @@ a+2b
# OP(not)
# 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.
% -not$a
# SYMBOL(%)
# WORD(-not$a)
& -not$a
# SYMBOL(&)
# 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.
% "-not$a"
# SYMBOL(%)
& "-not$a"
# SYMBOL(&)
# STR_START
# STRING(-not)
# VAR(a)