316 lines
7.3 KiB
C
316 lines
7.3 KiB
C
|
/*
|
||
|
* Copyright (C) 2007 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#undef NDEBUG
|
||
|
#include <assert.h>
|
||
|
#include "ast.h"
|
||
|
#include "execute.h"
|
||
|
|
||
|
typedef struct {
|
||
|
int c;
|
||
|
const char **v;
|
||
|
} StringList;
|
||
|
|
||
|
static int execBooleanValue(ExecContext *ctx,
|
||
|
const AmBooleanValue *booleanValue, bool *result);
|
||
|
static int execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
|
||
|
const char **result);
|
||
|
|
||
|
static int
|
||
|
execBooleanExpression(ExecContext *ctx,
|
||
|
const AmBooleanExpression *booleanExpression, bool *result)
|
||
|
{
|
||
|
int ret;
|
||
|
bool arg1, arg2;
|
||
|
bool unary;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(booleanExpression != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || booleanExpression == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
if (booleanExpression->op == AM_BOP_NOT) {
|
||
|
unary = true;
|
||
|
} else {
|
||
|
unary = false;
|
||
|
}
|
||
|
|
||
|
ret = execBooleanValue(ctx, booleanExpression->arg1, &arg1);
|
||
|
if (ret != 0) return ret;
|
||
|
|
||
|
if (!unary) {
|
||
|
ret = execBooleanValue(ctx, booleanExpression->arg2, &arg2);
|
||
|
if (ret != 0) return ret;
|
||
|
} else {
|
||
|
arg2 = false;
|
||
|
}
|
||
|
|
||
|
switch (booleanExpression->op) {
|
||
|
case AM_BOP_NOT:
|
||
|
*result = !arg1;
|
||
|
break;
|
||
|
case AM_BOP_EQ:
|
||
|
*result = (arg1 == arg2);
|
||
|
break;
|
||
|
case AM_BOP_NE:
|
||
|
*result = (arg1 != arg2);
|
||
|
break;
|
||
|
case AM_BOP_AND:
|
||
|
*result = (arg1 && arg2);
|
||
|
break;
|
||
|
case AM_BOP_OR:
|
||
|
*result = (arg1 || arg2);
|
||
|
break;
|
||
|
default:
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execFunctionArguments(ExecContext *ctx,
|
||
|
const AmFunctionArguments *functionArguments, StringList *result)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(functionArguments != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || functionArguments == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
result->c = functionArguments->argc;
|
||
|
result->v = (const char **)malloc(result->c * sizeof(const char *));
|
||
|
if (result->v == NULL) {
|
||
|
result->c = 0;
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
int i;
|
||
|
for (i = 0; i < functionArguments->argc; i++) {
|
||
|
ret = execStringValue(ctx, &functionArguments->argv[i], &result->v[i]);
|
||
|
if (ret != 0) {
|
||
|
result->c = 0;
|
||
|
free(result->v);
|
||
|
//TODO: free the individual args, if we're responsible for them.
|
||
|
result->v = NULL;
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execFunctionCall(ExecContext *ctx, const AmFunctionCall *functionCall,
|
||
|
const char **result)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(functionCall != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || functionCall == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
StringList args;
|
||
|
ret = execFunctionArguments(ctx, functionCall->args, &args);
|
||
|
if (ret != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
ret = callFunction(functionCall->fn, args.c, args.v, (char **)result, NULL);
|
||
|
if (ret != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
//TODO: clean up args
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execStringValue(ExecContext *ctx, const AmStringValue *stringValue,
|
||
|
const char **result)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(stringValue != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || stringValue == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
switch (stringValue->type) {
|
||
|
case AM_SVAL_LITERAL:
|
||
|
*result = strdup(stringValue->u.literal);
|
||
|
break;
|
||
|
case AM_SVAL_FUNCTION:
|
||
|
ret = execFunctionCall(ctx, stringValue->u.function, result);
|
||
|
if (ret != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execStringComparisonExpression(ExecContext *ctx,
|
||
|
const AmStringComparisonExpression *stringComparisonExpression,
|
||
|
bool *result)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(stringComparisonExpression != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || stringComparisonExpression == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
const char *arg1, *arg2;
|
||
|
ret = execStringValue(ctx, stringComparisonExpression->arg1, &arg1);
|
||
|
if (ret != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
ret = execStringValue(ctx, stringComparisonExpression->arg2, &arg2);
|
||
|
if (ret != 0) {
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int cmp = strcmp(arg1, arg2);
|
||
|
|
||
|
switch (stringComparisonExpression->op) {
|
||
|
case AM_SOP_LT:
|
||
|
*result = (cmp < 0);
|
||
|
break;
|
||
|
case AM_SOP_LE:
|
||
|
*result = (cmp <= 0);
|
||
|
break;
|
||
|
case AM_SOP_GT:
|
||
|
*result = (cmp > 0);
|
||
|
break;
|
||
|
case AM_SOP_GE:
|
||
|
*result = (cmp >= 0);
|
||
|
break;
|
||
|
case AM_SOP_EQ:
|
||
|
*result = (cmp == 0);
|
||
|
break;
|
||
|
case AM_SOP_NE:
|
||
|
*result = (cmp != 0);
|
||
|
break;
|
||
|
default:
|
||
|
return -__LINE__;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execBooleanValue(ExecContext *ctx, const AmBooleanValue *booleanValue,
|
||
|
bool *result)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(booleanValue != NULL);
|
||
|
assert(result != NULL);
|
||
|
if (ctx == NULL || booleanValue == NULL || result == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
switch (booleanValue->type) {
|
||
|
case AM_BVAL_EXPRESSION:
|
||
|
ret = execBooleanExpression(ctx, &booleanValue->u.expression, result);
|
||
|
break;
|
||
|
case AM_BVAL_STRING_COMPARISON:
|
||
|
ret = execStringComparisonExpression(ctx,
|
||
|
&booleanValue->u.stringComparison, result);
|
||
|
break;
|
||
|
default:
|
||
|
ret = -__LINE__;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
execCommand(ExecContext *ctx, const AmCommand *command)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
assert(ctx != NULL);
|
||
|
assert(command != NULL);
|
||
|
if (ctx == NULL || command == NULL) {
|
||
|
return -__LINE__;
|
||
|
}
|
||
|
|
||
|
CommandArgumentType argType;
|
||
|
argType = getCommandArgumentType(command->cmd);
|
||
|
switch (argType) {
|
||
|
case CMD_ARGS_BOOLEAN:
|
||
|
{
|
||
|
bool bVal;
|
||
|
ret = execBooleanValue(ctx, command->args->u.b, &bVal);
|
||
|
if (ret == 0) {
|
||
|
ret = callBooleanCommand(command->cmd, bVal);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case CMD_ARGS_WORDS:
|
||
|
{
|
||
|
AmWordList *words = command->args->u.w;
|
||
|
ret = callCommand(command->cmd, words->argc, words->argv);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
ret = -__LINE__;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
execCommandList(ExecContext *ctx, const AmCommandList *commandList)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < commandList->commandCount; i++) {
|
||
|
int ret = execCommand(ctx, commandList->commands[i]);
|
||
|
if (ret != 0) {
|
||
|
int line = commandList->commands[i]->line;
|
||
|
return line > 0 ? line : ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|