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;
 | |
| }
 |