copied everything over from 2012 and removed all of the actual robot code except the drivetrain stuff
git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4078 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/aos/build/act_builder.rb b/aos/build/act_builder.rb
new file mode 100644
index 0000000..d98549c
--- /dev/null
+++ b/aos/build/act_builder.rb
@@ -0,0 +1,242 @@
+require File.dirname(__FILE__) + "/parser.rb"
+
+module Contents
+ class HasEntry < SimpleField
+ end
+ class Priority < SimpleField
+ def initialize
+ super :is_number
+ end
+ end
+
+ class OutputFile
+ def fillin_initials
+ @args_struct = nil # string
+ @status_struct = nil # string
+ @action_name = nil # string
+ @actions = []
+ @has = []
+ end
+ def fillin_defaults
+ @action_name = @base unless @action_name
+ @actions.push @action_name if @actions.empty?
+ @args_struct.add_hidden_field 'timespec', 'set_time'
+ @status_struct.add_hidden_field 'timespec', 'set_time'
+ end
+ def parse_token token, tokenizer
+ case token
+ when 'args'
+ throw :syntax_error, '"args" redefined' if @args_struct
+ @args_struct = Struct.parse tokenizer
+ when 'status'
+ throw :syntax_error, '"status" redefined' if @status_struct
+ @status_struct = Struct.parse tokenizer
+ when 'action_name'
+ throw :syntax_error, '"action_name" redefined' if @action_name
+ @action_name = NameField.parse tokenizer
+ when 'async_queue'
+ @actions.push(NameField.parse tokenizer)
+ when 'has'
+ @has.push(HasEntry.parse tokenizer)
+ when 'priority'
+ throw :syntax_error, '"priority" redefined' if @priority
+ @priority = Priority.parse tokenizer
+ else
+ throw :syntax_error, "unsupported field \"#{token}\""
+ end
+ end
+ def check_format tokenizer
+ tokenizer.item_missing("args") unless @args_struct
+ tokenizer.item_missing("status") unless @status_struct
+ tokenizer.item_missing("priority") unless @priority
+ end
+
+ def superclass
+ "aos::AsyncAction<#{@args_struct.name}, #{@status_struct.name}>"
+ end
+ def impl_class
+ @action_name + '_t'
+ end
+ def handle_class
+ @action_name + 'Handle'
+ end
+ def write_header
+ f = File.open(filename('h'), "w+")
+ f.puts <<END
+#ifndef AOS_GENERATED_ASYNC_ACTION_#{impl_class}_H_
+#define AOS_GENERATED_ASYNC_ACTION_#{impl_class}_H_
+// This file is autogenerated.
+// Edit #{@filename} to change its contents.
+
+#include "aos/common/messages/QueueHolder.h"
+#include "aos/atom_code/async_action/AsyncAction.h"
+#include "aos/atom_code/async_action/AsyncActionHandle.h"
+
+namespace #{$namespace} {
+#{@args_struct.writer}
+#{@status_struct.writer}
+ class #{impl_class} : public #{superclass} {
+ virtual void DoAction(#{@args_struct.name} &args __attribute__((unused))){
+ DoAction(#{@args_struct.params_from 'args'});
+ }
+ void DoAction(#{@args_struct.params});
+#{@has.grep('OnStart').empty? ? '' : "virtual void OnStart();"}
+#{@has.grep('OnEnd').empty? ? '' : "virtual void OnEnd();"}
+ using #{superclass}::PostStatus;
+ inline void PostStatus(#{@status_struct.params}){
+ #{@status_struct.copy_params_into 'new_stat'}
+ PostStatus(new_stat);
+ }
+ public:
+ #{impl_class}(const std::string name) : #{superclass}(name) {}
+#ifdef AOS_#{impl_class}_HEADER_FRAG
+ AOS_#{impl_class}_HEADER_FRAG
+#endif
+ };
+
+ class #{handle_class} : public aos::AsyncActionHandle {
+ friend class ::AsyncActionTest;
+ private:
+ const std::string name;
+ #{superclass} *instance;
+ #{superclass} &GetInstance(){
+ if(instance == NULL){
+ instance = new #{superclass}(name);
+ }
+ return *instance;
+ }
+ #{@status_struct.name} temp_status;
+ void Free(){
+ if(instance != NULL){
+ delete instance;
+ instance = NULL;
+ }
+ }
+ public:
+ inline uint16_t Start(#{@args_struct.name} &args){
+ return GetInstance().Start(args);
+ }
+ inline uint16_t Start(#{@args_struct.params}){
+ #{@args_struct.copy_params_into 'args_struct'}
+ return Start(args_struct);
+ }
+ inline void Execute(#{@args_struct.name} &args){
+ GetInstance().Join(GetInstance().Start(args));
+ }
+ inline bool Execute(#{@args_struct.params}){
+ #{@args_struct.copy_params_into 'args_struct'}
+ Execute(args_struct);
+ return GetStatus();
+ }
+ inline bool IsDone(){
+ return GetInstance().IsDone();
+ }
+ inline bool IsDone(int32_t count){
+ return GetInstance().IsDone(count);
+ }
+ inline uint16_t Join(){
+ return GetInstance().Join();
+ }
+ inline uint16_t Join(int32_t count){
+ return GetInstance().Join(count);
+ }
+ inline bool GetStatus(#{@status_struct.name} &status_out) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetStatus(status_out);
+ }
+ inline bool GetStatus(#{@status_struct.name} &status_out, int32_t count) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetStatus(status_out, count);
+ }
+ inline bool GetStatus() __attribute__ ((warn_unused_result)){
+ return GetInstance().GetStatus(temp_status);
+ }
+ inline bool GetStatus(int32_t count) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetStatus(temp_status, count);
+ }
+ inline bool GetNextStatus(#{@status_struct.name} &status_out) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetNextStatus(status_out);
+ }
+ inline bool GetNextStatus(#{@status_struct.name} &status_out, int32_t count) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetNextStatus(status_out, count);
+ }
+ inline bool GetNextStatus() __attribute__ ((warn_unused_result)){
+ return GetInstance().GetNextStatus(temp_status);
+ }
+ inline bool GetNextStatus(int32_t count) __attribute__ ((warn_unused_result)){
+ return GetInstance().GetNextStatus(temp_status, count);
+ }
+ inline const #{@status_struct.name} &GetLastStatus(){
+ return temp_status;
+ }
+ inline void Stop(){
+ GetInstance().Stop();
+ }
+ inline void Stop(int32_t count){
+ GetInstance().Stop(count);
+ }
+
+ #{handle_class}(const std::string name) : name(name), instance(NULL) {}
+ };
+#{(@actions.collect do |a|
+<<END2
+ extern #{handle_class} #{a};
+END2
+end).join('')}
+
+} // namespace #{$namespace}
+
+#endif
+END
+ f.close
+ end
+ def write_cpp
+ f = File.open(filename('cc'), "w+")
+f.puts <<END
+// This file is autogenerated.
+// Edit #{@filename} to change its contents.
+
+#include "#{filename 'h'}"
+
+namespace #{$namespace} {
+
+#{(@actions.collect do |a|
+<<END2
+#{handle_class} #{a}("#{a}");
+END2
+end).join("\n")}
+
+} // namespace #{$namespace}
+END
+ f.close
+ end
+ def write_main
+ f = File.open(filename('main'), "w+")
+f.puts <<END
+// This file is autogenerated.
+// Edit #{@filename} to change its contents.
+
+#include "#{filename 'h'}"
+#include "aos/atom_code/async_action/AsyncActionRunner.h"
+#include <string>
+#include <cstring>
+#include <iostream>
+
+int main(int argc, char **argv) {
+ aos::Init();
+
+ std::string name = "#{@action_name}";
+ if(argc > 1)
+ name = std::string(argv[1]);
+ #{$namespace}::#{impl_class} action(name);
+ int rv = aos::AsyncActionRunner::Run(action, #{@priority});
+
+ aos::Cleanup();
+ return rv;
+}
+END
+ f.close
+ end
+ end
+end
+
+write_file_out
+
diff --git a/aos/build/aos.gyp b/aos/build/aos.gyp
new file mode 100644
index 0000000..b6bd3ee
--- /dev/null
+++ b/aos/build/aos.gyp
@@ -0,0 +1,156 @@
+# This file has all of the aos targets.
+# For the cRIO, shared_library means to build a .out file, NOT a shared library.
+# This means that depending on shared libraries doesn't work very well.
+# Shared libraries don't seem to be supported by the powerpc-wrs-vxworks
+# tools and gyp doesn't like a static_library that depends on static_librarys.
+{
+ 'variables': {
+ 'conditions': [
+ ['OS=="crio"', {
+ 'libaos_source_files': [
+ '<!@(find <(AOS)/crio/controls <(AOS)/crio/messages <(AOS)/crio/motor_server <(AOS)/crio/shared_libs -name *.c -or -name *.cpp -or -name *.cc)',
+ '<(AOS)/crio/Talon.cpp',
+ '<(AOS)/common/die.cc',
+ ],
+ }, {
+ 'libaos_source_files': [
+ '<(AOS)/atom_code/camera/Buffers.cpp',
+ '<(AOS)/atom_code/async_action/AsyncAction_real.cpp',
+ '<(AOS)/atom_code/init.cc',
+ '<(AOS)/atom_code/ipc_lib/mutex.cpp',
+ '<(AOS)/common/die.cc',
+ ],
+ }
+ ],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'logging',
+ 'type': 'static_library',
+ 'conditions': [
+ ['OS=="crio"', {
+ 'sources': [
+ '<(AOS)/crio/logging/crio_logging.cpp',
+ ],
+ 'dependencies': [
+ '<(EXTERNALS):WPILib',
+ ]
+ }, {
+ 'sources': [
+ '<(AOS)/atom_code/logging/atom_logging.cpp'
+ ],
+ 'dependencies': [
+ '<(AOS)/atom_code/ipc_lib/ipc_lib.gyp:ipc_lib',
+ ],
+ 'export_dependent_settings': [
+ '<(AOS)/atom_code/ipc_lib/ipc_lib.gyp:ipc_lib',
+ ]
+ }],
+ ],
+ 'dependencies': [
+ '<(AOS)/common/common.gyp:time',
+ ],
+ },
+ {
+# Private to make Brian happy. Don't use elsewhere in so targets or risk things
+# breaking.
+ 'target_name': 'aos_swig',
+ 'type': 'static_library',
+ 'sources': [
+ '<(AOS)/aos.swig',
+ ],
+ 'variables': {
+ 'package': 'aos',
+ },
+ 'dependencies': [
+ '<(AOS)/common/common.gyp:queues',
+ ],
+ 'includes': ['../build/swig.gypi'],
+ },
+ {
+ 'target_name': 'libaos',
+ 'type': 'static_library',
+ 'sources': ['<@(libaos_source_files)'],
+ 'sources/': [['exclude', '_test\.c[cp]*$']],
+ 'dependencies': [
+ '<(AOS)/common/messages/messages.gyp:aos_queues',
+ 'logging',
+ '<(EXTERNALS):WPILib',
+ ],
+ 'export_dependent_settings': [
+ '<(AOS)/common/messages/messages.gyp:aos_queues',
+ '<(EXTERNALS):WPILib',
+ ],
+ 'conditions': [
+ ['OS=="atom"', {
+ 'dependencies': [
+ '<(AOS)/atom_code/ipc_lib/ipc_lib.gyp:ipc_lib',
+ ],
+ }]
+ ],
+ },
+ {
+ 'target_name': 'aos_shared_lib',
+ 'type': 'shared_library',
+ 'sources': ['<@(libaos_source_files)'],
+ 'sources/': [['exclude', '_test\.c[cp]*$']],
+ 'variables': {'no_rsync': 1},
+ 'dependencies': [
+ '<(AOS)/common/messages/messages.gyp:queues_so',
+ '<(AOS)/common/common.gyp:queues',
+ 'aos_swig',
+ '<(EXTERNALS):WPILib',
+ ],
+ 'export_dependent_settings': [
+ '<(AOS)/common/messages/messages.gyp:queues_so',
+ '<(EXTERNALS):WPILib',
+ 'aos_swig',
+ ],
+ 'direct_dependent_settings': {
+ 'variables': {
+ 'jni_libs': [
+ 'aos_shared_lib',
+ ],
+ },
+ },
+ },
+ {
+# A target that has all the same dependencies as libaos and aos_shared_lib
+# without any queues so that the queues can get the necessary headers without
+# creating circular dependencies.
+ 'target_name': 'aos_internal_nolib',
+ 'type': 'none',
+ 'dependencies': [
+ 'aos/ResourceList.h',
+ '<(EXTERNALS):WPILib',
+ ],
+ 'export_dependent_settings': [
+ 'aos/ResourceList.h',
+ '<(EXTERNALS):WPILib',
+ ],
+ },
+ {
+ 'target_name': 'aos/ResourceList.h',
+ 'type': 'static_library',
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(SHARED_INTERMEDIATE_DIR)/ResourceList',
+ ],
+ },
+ 'hard_dependency': 1,
+ 'actions': [
+ {
+ 'variables': {
+ 'script': '<(AOS)/build/gen_resource_list.rb'
+ },
+ 'action_name': 'gen_aos_ResourceList_h',
+ 'inputs': ['<(script)'],
+ 'outputs': ['<(SHARED_INTERMEDIATE_DIR)/ResourceList/aos/ResourceList.h'],
+ 'message': 'Generating',
+ 'action': ['ruby', '<(script)', '<(SHARED_INTERMEDIATE_DIR)/ResourceList/aos',],
+ },
+ ],
+ },
+ ],
+}
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
new file mode 100644
index 0000000..08bf975
--- /dev/null
+++ b/aos/build/aos.gypi
@@ -0,0 +1,194 @@
+# This file gets passed to gyp with -I so that it gets included everywhere.
+{
+ 'variables': {
+ 'AOS': '<(DEPTH)/aos',
+# A directory with everything in it ignored from source control.
+ 'TMPDIR': '<(DEPTH)/aos/build/temp',
+ 'aos_abs': '<!(readlink -f <(DEPTH)/aos)', # for use in non-path contexts
+# the .gyp file that has targets for the various external libraries
+ 'EXTERNALS': '<(AOS)/build/externals.gyp',
+# the directory that gets rsynced to the atom
+ 'rsync_dir': '<(PRODUCT_DIR)/outputs',
+# The directory that loadable_module and shared_library targets get put into
+# There's a target_conditions that puts loadable_modules here and
+# shared_librarys automatically get put here.
+ 'so_dir': '<(PRODUCT_DIR)/lib',
+# the directory that executables that depend on <(EXTERNALS):gtest get put into
+ 'test_dir': '<(PRODUCT_DIR)/tests',
+# 'executable' for the atom and 'static_library' for the cRIO
+# Useful for targets that should either be an executable or get compiled into
+# a .out file depending on the current platform.
+# 'aos_target': platform-dependent,
+ },
+ 'conditions': [
+ ['OS=="crio"', {
+ 'make_global_settings': [
+ ['CC', '<!(which powerpc-wrs-vxworks-gcc)'],
+ ['CXX', '<!(which powerpc-wrs-vxworks-g++)'],
+ ['LD', '<!(readlink -f <(AOS)/build/crio_link_out)'],
+ #['LD', 'powerpc-wrs-vxworks-ld'],
+ #['AR', '<!(which powerpc-wrs-vxworks-ar)'],
+ #['NM', '<!(which powerpc-wrs-vxworks-nm)'],
+ ],
+ 'variables': {
+ 'aos_target': 'static_library',
+ },
+ }, {
+ 'variables': {
+ 'aos_target': 'executable',
+ },
+ }
+ ],
+ ],
+ 'target_defaults': {
+ 'defines': [
+ '__STDC_FORMAT_MACROS',
+ '_FORTIFY_SOURCE=2',
+ ],
+ 'ldflags': [
+ '-pipe',
+ ],
+ 'cflags': [
+ '-pipe',
+
+ '-Wall',
+ '-Wextra',
+ '-Wswitch-enum',
+ '-Wpointer-arith',
+ '-Wstrict-aliasing=2',
+ '-Wcast-qual',
+ '-Wcast-align',
+ '-Wwrite-strings',
+ '-Wtype-limits',
+ '-Wsign-compare',
+ '-Wformat=2',
+ '-Werror',
+ ],
+ 'cflags_c': [
+ '-std=gnu99',
+ ],
+ 'cflags_cc': [
+ '-std=gnu++0x',
+ ],
+ 'include_dirs': [
+ '<(DEPTH)',
+ ],
+ 'conditions': [
+ ['DEBUG=="yes"', {
+ 'cflags': [
+ '-ggdb3',
+ '-O0',
+ ],
+ 'ldflags': [
+ '-O3',
+ ],
+ }, {
+ 'cflags': [
+ '-O3',
+ ],
+ 'conditions': [['OS=="crio"', {
+ 'cflags': [
+ '-fstrength-reduce',
+ '-fno-builtin',
+ '-fno-strict-aliasing',
+ ],
+ }, {
+ 'cflags': [
+ # core2 says the same stuff as atom in the gcc docs but is supported by 4.4.5
+ '-march=core2',
+ '-mtune=generic',
+ '-msse3',
+ '-mfpmath=sse',
+
+ '-fstack-protector',
+ ],
+ }
+ ]],
+ }
+ ],
+ ['OS=="crio"', {
+ 'target_conditions': [
+ ['_type=="shared_library"', {
+ 'ldflags': [
+ '-r',
+ '-nostdlib',
+ '-Wl,-X',
+ ],
+ }
+ ],
+ ],
+ 'ldflags': [
+ '-mcpu=603',
+ '-mstrict-align',
+ '-mlongcall',
+ ],
+ 'cflags': [
+ '-mcpu=603',
+ '-mstrict-align',
+ '-mlongcall',
+ '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/lib/gcc/powerpc-wrs-vxworks/3.4.4/include/',
+ '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/vxworks-6.3/target/h/',
+ '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/',
+ '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/powerpc-wrs-vxworks/',
+ '-isystem', '<(WIND_BASE)/target/h',
+ '-isystem', '<(WIND_BASE)/target/h/wrn/coreip',
+ ],
+ 'defines': [
+ 'CPU=PPC603',
+ 'TOOL_FAMILY=gnu',
+ 'TOOL=gnu',
+ '_WRS_KERNEL',
+ '__PPC__',
+# This tells eigen to not do anything with alignment at all. See
+# <http://eigen.tuxfamily.org/dox/TopicPreprocessorDirectives.html> for
+# details. It really doesn't like to work without this.
+ 'EIGEN_DONT_ALIGN',
+# prevent the vxworks system headers from being dumb and #defining min and max
+ 'NOMINMAX',
+ ],
+ }, {
+ 'variables': {
+ 'no_rsync%': 0,
+ },
+ 'target_conditions': [
+# default to putting outputs into rsync_dir
+ ['no_rsync==0 and _type!="static_library"', {
+ 'product_dir': '<(rsync_dir)',
+ },
+ ],
+ ['_type=="loadable_module"', {
+ 'product_dir': '<(so_dir)',
+ }
+ ],
+ ['_type=="loadable_module" or _type=="shared_library"', {
+ 'ldflags': [
+# Support loading other shared objects that are in the same directory but not
+# the shared object load path. Required for using the swig-generated libs.
+ '-Wl,-rpath=\\$$ORIGIN',
+ ],
+ }
+ ],
+ ],
+ 'ldflags': [
+ '-pthread',
+ '-m32',
+ ],
+ 'library_dirs': [
+ '/usr/lib32',
+ ],
+ 'cflags': [
+ '-pthread',
+ '-m32',
+ ],
+ 'defines': [
+ '_LARGEFILE64_SOURCE',
+ ],
+ 'libraries': [
+ '-lm',
+ '-lrt',
+ ],
+ }
+ ]
+ ],
+ },
+}
diff --git a/aos/build/aos_all.gyp b/aos/build/aos_all.gyp
new file mode 100644
index 0000000..a65909d
--- /dev/null
+++ b/aos/build/aos_all.gyp
@@ -0,0 +1,48 @@
+# This file has the executables etc that AOS builds.
+# User .gyp files for the atom should depend on :Atom.
+# User .gyp files for the crio should depend on :Crio.
+{
+ 'targets': [
+ {
+ 'target_name': 'Atom',
+ 'type': 'none',
+ 'variables': {
+ 'no_rsync': 1,
+ },
+ 'dependencies': [
+ '../atom_code/camera/camera.gyp:CameraHTTPStreamer',
+ '../atom_code/camera/camera.gyp:CameraReader',
+ '../atom_code/core/core.gyp:*',
+ #'../atom_code/async_action:*', # TODO(brians) fix this broken test
+ '../atom_code/ipc_lib/ipc_lib.gyp:*',
+ '../atom_code/starter/starter.gyp:*',
+ '../crio/crio.gyp:unsafe_queue_test',
+ '../common/common.gyp:queue_test',
+ #'../common/messages/messages.gyp:*', # TODO(brians) did this test ever exist?
+ '../atom_code/logging/logging.gyp:*',
+ '../common/common.gyp:die_test',
+ ':Common',
+ ],
+ },
+ {
+ 'target_name': 'Crio',
+ 'type': 'none',
+ 'dependencies': [
+ '../crio/googletest/googletest.gyp:*',
+ ':Common',
+ ],
+ },
+ {
+ 'target_name': 'Common',
+ 'type': 'none',
+ 'variables': {
+ 'no_rsync': 1,
+ },
+ 'dependencies': [
+ '<(AOS)/common/common.gyp:type_traits_test',
+ '<(AOS)/common/common.gyp:time_test',
+ '<(AOS)/common/common.gyp:mutex_test',
+ ],
+ },
+ ],
+}
diff --git a/aos/build/build.sh b/aos/build/build.sh
new file mode 100755
index 0000000..7c0362b
--- /dev/null
+++ b/aos/build/build.sh
@@ -0,0 +1,81 @@
+#!/bin/bash -e
+#set -x
+
+# This file should be called to build the code.
+# Usage: build.sh platform main_file.gyp debug [action]
+
+PLATFORM=$1
+GYP_MAIN=$2
+DEBUG=$3
+ACTION=$4
+
+export WIND_BASE=${WIND_BASE:-"/usr/local/powerpc-wrs-vxworks/wind_base"}
+
+[ ${PLATFORM} == "crio" -o ${PLATFORM} == "atom" ] || ( echo Platform "(${PLATFORM})" must be '"crio" or "atom"'. ; exit 1 )
+[ ${DEBUG} == "yes" -o ${DEBUG} == "no" ] || ( echo Debug "(${DEBUG})" must be '"yes" or "no"'. ; exit 1 )
+
+AOS=`dirname $0`/..
+NINJA_DIR=${AOS}/externals/ninja
+NINJA=${NINJA_DIR}/ninja
+# From chromium@154360:trunk/src/DEPS.
+GYP_REVISION=1488
+GYP_DIR=${AOS}/externals/gyp-${GYP_REVISION}
+GYP=${GYP_DIR}/gyp
+
+OUTDIR=${AOS}/../out_${PLATFORM}
+BUILD_NINJA=${OUTDIR}/Default/build.ninja
+
+[ -d ${NINJA_DIR} ] || git clone --branch release https://github.com/martine/ninja.git ${NINJA_DIR}
+[ -x ${NINJA} ] || ${NINJA_DIR}/bootstrap.py
+[ -d ${GYP_DIR} ] || ( svn co http://gyp.googlecode.com/svn/trunk -r ${GYP_REVISION} ${GYP_DIR} && patch -p1 -d ${GYP_DIR} < ${AOS}/externals/gyp.patch )
+${AOS}/build/download_externals.sh
+
+# The exciting quoting is so that it ends up with -DWHATEVER='"'`a command`'"'.
+# The '"' at either end is so that it creates a string constant when expanded
+# in the C/C++ code.
+COMMONFLAGS='-DLOG_SOURCENAME='"'\"'"'`basename $in`'"'\"' "
+if [ ${PLATFORM} == crio ]; then
+ COMMONFLAGS+='-DAOS_INITNAME=aos_init_function_`readlink -f $out | sed \"s/[\/.]/_/g\"` '
+fi
+
+if [[ "${ACTION}" != "clean" && ( ! -d ${OUTDIR} || -n \
+ "`find ${AOS}/.. -newer ${BUILD_NINJA} \( -name '*.gyp' -or -name '*.gypi' \)`" ) ]]; then
+ ${GYP} \
+ --check --depth=${AOS}/.. --no-circular-check -f ninja \
+ -I${AOS}/build/aos.gypi -Goutput_dir=out_${PLATFORM} \
+ -DOS=${PLATFORM} -DWIND_BASE=${WIND_BASE} -DDEBUG=${DEBUG} \
+ ${GYP_MAIN}
+ # Have to substitute "command = $compiler" so that it doesn't try to
+ # substitute them in the linker commands, where it doesn't work.
+ sed -i "s:command = \$cc:\\0 ${COMMONFLAGS}:g ; \
+ s:command = \$cxx:\\0 ${COMMONFLAGS}:g" \
+ ${BUILD_NINJA}
+ if [ ${PLATFORM} == crio ]; then
+ sed -i 's/nm -gD/nm/g' ${BUILD_NINJA}
+ fi
+fi
+
+if [ "${ACTION}" == "clean" ]; then
+ rm -r ${OUTDIR}
+else
+ if [ "${ACTION}" != "deploy" -a "${ACTION}" != "tests" ]; then
+ GYP_ACTION=${ACTION}
+ else
+ GYP_ACTION=
+ fi
+ ${NINJA} -C ${OUTDIR}/Default ${GYP_ACTION}
+ case ${ACTION} in
+ deploy)
+ [ ${PLATFORM} == atom ] && \
+ rsync --progress -t -r --rsync-path=/home/driver/bin/rsync \
+ ${OUTDIR}/Default/outputs/* \
+ driver@fitpc:/home/driver/robot_code/bin
+ [ ${PLATFORM} == crio ] && \
+ ncftpput robot / \
+ ${OUTDIR}/Default/lib/FRC_UserProgram.out
+ ;;
+ tests)
+ find ${OUTDIR}/Default/tests -executable -exec {} \;
+ ;;
+ esac
+fi
diff --git a/aos/build/create_aos_ctdt.sh b/aos/build/create_aos_ctdt.sh
new file mode 100755
index 0000000..63c927c
--- /dev/null
+++ b/aos/build/create_aos_ctdt.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+echo '#include "aos/crio/aos_ctdt.h"'
+calls=''
+for symbol in `cat - | awk '{ print $NF }' | grep '^aos_init_function_'`; do
+ echo "void $symbol();"
+ calls="$calls$symbol();\n"
+done
+echo 'void aos_call_init_functions() {'
+echo -e $calls
+echo '}'
+
diff --git a/aos/build/create_jar b/aos/build/create_jar
new file mode 100755
index 0000000..2ef496e
--- /dev/null
+++ b/aos/build/create_jar
@@ -0,0 +1,29 @@
+#!/bin/bash
+source `dirname $0`/jdk_tools_common
+
+# This is a helper script that compiles java files into a jar.
+
+SOURCEFILEPARENTDIRS=`echo $4 | tr -d '"'`
+SOURCEFILEDIRS=`echo $1 | tr -d '"'`
+[ -n "${SOURCEFILEPARENTDIRS}" ] && SOURCEFILEDIRS+=" `find ${SOURCEFILEPARENTDIRS} -type d -maxdepth 1`"
+SOURCEFILES=`find ${SOURCEFILEDIRS} -name *.java`
+MANIFEST_FILE=$5
+OUTPUT_JAR=$6
+HEADER_DIR=$7
+GEN_HEADERS=$8
+
+CLASSFILES_DIR=${TMPDIR}/classfiles
+
+[ -a ${CLASSFILES_DIR} ] && rm -r ${CLASSFILES_DIR}
+mkdir ${CLASSFILES_DIR}
+[ -a ${HEADER_DIR} ] && rm -r ${HEADER_DIR}
+mkdir -p ${HEADER_DIR}
+
+javac -d ${CLASSFILES_DIR} -classpath "${EXTRA_CLASSPATH}" ${SOURCEFILES}
+
+jar cfm ${OUTPUT_JAR} ${MANIFEST_FILE} \
+ `find ${CLASSFILES_DIR} -name *.class | \
+ sed "s:${CLASSFILES_DIR}/\(.*\):-C ${CLASSFILES_DIR} \1:g"`
+
+[ -z ${GEN_HEADERS} ] || javah -d ${HEADER_DIR} \
+ -classpath "${EXTRA_CLASSPATH}:${OUTPUT_JAR}" ${GEN_HEADERS}
diff --git a/aos/build/create_onejar b/aos/build/create_onejar
new file mode 100755
index 0000000..aa7ecd5
--- /dev/null
+++ b/aos/build/create_onejar
@@ -0,0 +1,26 @@
+#!/bin/bash
+source `dirname $0`/jdk_tools_common
+
+# This is a helper script that puts jars into a OneJAR package.
+
+MAIN_JAR=$1
+OUTPUT_ONEJAR=$4
+ONEJAR_JAR=$5
+SHARED_OBJECTS=$6
+
+JAR_DIR=${TMPDIR}/jardir
+
+# the dir name in the jar under which shared objects get put
+BINLIB_DIR=so_libs
+
+[ -a ${JAR_DIR} ] && rm -r ${JAR_DIR}
+mkdir ${JAR_DIR} ${JAR_DIR}/main ${JAR_DIR}/lib ${JAR_DIR}/${BINLIB_DIR}
+
+cp ${EXTRA_JARS} ${JAR_DIR}/lib
+cp ${SHARED_OBJECTS} ${JAR_DIR}/${BINLIB_DIR}
+cp ${MAIN_JAR} ${JAR_DIR}/main/main.jar
+
+unzip -q -d ${JAR_DIR} ${ONEJAR_JAR}
+cp ${JAR_DIR}/boot-manifest.mf ${TMPDIR}/manifest.mf
+echo "One-Jar-Expand: ${BINLIB_DIR}" >> ${TMPDIR}/manifest.mf
+jar cfm ${OUTPUT_ONEJAR} ${TMPDIR}/manifest.mf -C ${JAR_DIR} .
diff --git a/aos/build/crio_link_out b/aos/build/crio_link_out
new file mode 100755
index 0000000..eef549b
--- /dev/null
+++ b/aos/build/crio_link_out
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# This is a helper script that compiles .out files for the cRIO. It is designed
+# to be called as a replacement for g++ being used as a linker.
+
+# All the flags except -shared.
+INPUTS_FLAGS=`echo "$@" | sed 's/-shared//g'`
+# The arguments after any -o flags.
+OUTPUT=`echo ${INPUTS_FLAGS} | awk \
+ 'BEGIN { RS=" " }; output { print ; output = 0 }; /-o/ { output = 1 }'`
+# All arguments that don't start with a - and aren't ${OUTPUT}.
+#INPUTS=`echo ${INPUTS_FLAGS} | sed "s:-[^ ]*::g; s:${OUTPUT}::g;"`
+INPUTS=`echo ${INPUTS_FLAGS} | awk \
+ 'BEGIN { RS=" " }; /-Wl,--no-whole-archive/ { output = 0 }; \
+ output { print }; \
+ /-Wl,--whole-archive/ { output = 1 }'`
+TEMPDIR=`dirname ${OUTPUT}`
+AOS=`dirname $0`/..
+powerpc-wrs-vxworks-nm ${INPUTS} | \
+ tclsh ${WIND_BASE}/host/resource/hutils/tcl/munch.tcl -c ppc > ${TEMPDIR}/ctdt.c
+powerpc-wrs-vxworks-gcc -I${AOS}/.. -c ${TEMPDIR}/ctdt.c -o ${TEMPDIR}/ctdt.o
+powerpc-wrs-vxworks-nm ${INPUTS} | \
+ ${AOS}/build/create_aos_ctdt.sh > ${TEMPDIR}/aos_ctdt.c
+powerpc-wrs-vxworks-gcc -I${AOS}/.. -c ${TEMPDIR}/aos_ctdt.c -o ${TEMPDIR}/aos_ctdt.o
+powerpc-wrs-vxworks-g++ ${INPUTS_FLAGS} ${TEMPDIR}/ctdt.o ${TEMPDIR}/aos_ctdt.o
+ln -f ${OUTPUT} `echo ${OUTPUT} | sed 's/lib\([A-Za-z0-9_]*\)\.so$/\1.out/'`
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
new file mode 100755
index 0000000..ef843e1
--- /dev/null
+++ b/aos/build/download_externals.sh
@@ -0,0 +1,62 @@
+#!/bin/bash -e
+
+AOS=`dirname $0`/..
+EXTERNALS=${AOS}/externals
+
+# get gccdist
+GCCDIST=${EXTERNALS}/gccdist
+[ -f ${GCCDIST}.zip ] || wget ftp://ftp.ni.com/pub/devzone/tut/updated_vxworks63gccdist.zip -O ${GCCDIST}.zip
+[ -d ${GCCDIST} ] || ( cd ${EXTERNALS} && unzip -q ${GCCDIST}.zip )
+
+# get eigen
+EIGEN_VERSION=3.0.5
+EIGEN_DIR=${EXTERNALS}/eigen-${EIGEN_VERSION}
+[ -f ${EIGEN_DIR}.tar.bz2 ] || wget http://bitbucket.org/eigen/eigen/get/${EIGEN_VERSION}.tar.bz2 -O ${EIGEN_DIR}.tar.bz2
+[ -d ${EIGEN_DIR} ] || ( mkdir ${EIGEN_DIR} && tar --strip-components=1 -C ${EIGEN_DIR} -xf ${EIGEN_DIR}.tar.bz2 )
+
+# get the javacv binaries
+JAVACV_VERSION=0.2
+JAVACV_DIR=${EXTERNALS}/javacv-bin
+JAVACV_ZIP=${EXTERNALS}/javacv-${JAVACV_VERSION}-bin.zip
+[ -f ${JAVACV_ZIP} ] || wget http://javacv.googlecode.com/files/javacv-${JAVACV_VERSION}-bin.zip -O ${JAVACV_ZIP}
+[ -d ${JAVACV_DIR} ] || ( cd ${EXTERNALS} && unzip ${JAVACV_ZIP} )
+
+# get the simple one-jar template jar
+ONEJAR_VERSION=0.97
+ONEJAR_JAR=${EXTERNALS}/one-jar-boot-${ONEJAR_VERSION}.jar
+[ -f ${ONEJAR_JAR} ] || wget http://sourceforge.net/projects/one-jar/files/one-jar/one-jar-${ONEJAR_VERSION}/one-jar-boot-${ONEJAR_VERSION}.jar/download -O ${ONEJAR_JAR}
+
+# get and build libjpeg
+LIBJPEG_VERSION=8d
+LIBJPEG_DIR=${EXTERNALS}/jpeg-${LIBJPEG_VERSION}
+# NOTE: this directory ends up in #include names
+LIBJPEG_PREFIX=${EXTERNALS}/libjpeg
+LIBJPEG_LIB=${LIBJPEG_PREFIX}/lib/libjpeg.a
+LIBJPEG_TAR=${EXTERNALS}/jpegsrc.v${LIBJPEG_VERSION}.tar.gz
+[ -f ${LIBJPEG_TAR} ] || wget http://www.ijg.org/files/jpegsrc.v${LIBJPEG_VERSION}.tar.gz -O ${LIBJPEG_TAR}
+[ -d ${LIBJPEG_DIR} ] || ( mkdir ${LIBJPEG_DIR} && tar --strip-components=1 -C ${LIBJPEG_DIR} -xf ${LIBJPEG_TAR} )
+[ -f ${LIBJPEG_LIB} ] || env -i PATH="${PATH}" bash -c "cd ${LIBJPEG_DIR} && CFLAGS='-m32' ./configure --disable-shared --prefix=`readlink -f ${LIBJPEG_PREFIX}` && make && make install"
+
+# get gtest
+GTEST_VERSION=1.6.0
+GTEST_DIR=${EXTERNALS}/gtest-${GTEST_VERSION}-p1
+GTEST_ZIP=${EXTERNALS}/gtest-${GTEST_VERSION}.zip
+TMPDIR=/tmp/$$-aos-tmpdir
+[ -f ${GTEST_ZIP} ] || wget http://googletest.googlecode.com/files/gtest-${GTEST_VERSION}.zip -O ${GTEST_ZIP}
+[ -d ${GTEST_DIR} ] || ( unzip ${GTEST_ZIP} -d ${TMPDIR} && mv ${TMPDIR}/gtest-${GTEST_VERSION} ${GTEST_DIR} && cd ${GTEST_DIR} && patch -p1 < ../gtest.patch )
+
+# get and build ctemplate
+CTEMPLATE_VERSION=2.2
+CTEMPLATE_DIR=${EXTERNALS}/ctemplate-${CTEMPLATE_VERSION}
+CTEMPLATE_PREFIX=${CTEMPLATE_DIR}-prefix
+CTEMPLATE_LIB=${CTEMPLATE_PREFIX}/lib/libctemplate.a
+CTEMPLATE_URL=http://ctemplate.googlecode.com/files
+CTEMPLATE_URL=${CTEMPLATE_URL}/ctemplate-${CTEMPLATE_VERSION}.tar.gz
+[ -f ${CTEMPLATE_DIR}.tar.gz ] || \
+ wget ${CTEMPLATE_URL} -O ${CTEMPLATE_DIR}.tar.gz
+[ -d ${CTEMPLATE_DIR} ] || ( mkdir ${CTEMPLATE_DIR} && tar \
+ --strip-components=1 -C ${CTEMPLATE_DIR} -xf ${CTEMPLATE_DIR}.tar.gz )
+[ -f ${CTEMPLATE_LIB} ] || env -i PATH="${PATH}" \
+ CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
+ bash -c "cd ${CTEMPLATE_DIR} && ./configure --disable-shared \
+ --prefix=`readlink -f ${CTEMPLATE_PREFIX}` && make && make install"
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
new file mode 100644
index 0000000..2ed0478
--- /dev/null
+++ b/aos/build/externals.gyp
@@ -0,0 +1,133 @@
+# This file has targets for various external libraries.
+# download_externals.sh makes sure that all of them have been downloaded.
+{
+ 'variables': {
+ 'externals': '<(AOS)/externals',
+ 'externals_abs': '<!(readlink -f ../externals)',
+
+# These versions have to be kept in sync with the ones in download_externals.sh.
+ 'eigen_version': '3.0.5',
+ 'gtest_version': '1.6.0-p1',
+ 'onejar_version': '0.97',
+ 'ctemplate_version': '2.2',
+ },
+ 'targets': [
+ {
+# does nothing when OS!="crio"
+ 'target_name': 'WPILib',
+ 'type': 'none',
+ 'conditions': [['OS=="crio"', {
+ 'direct_dependent_settings': {
+ 'cflags': [
+ '-isystem', '<(aos_abs)/externals/WPILib',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '<(aos_abs)/externals/WPILib/WPILib.a',
+ ],
+ },
+ },
+ }]],
+ },
+ {
+ 'target_name': 'onejar',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'variables': {
+ 'onejar_jar': '<(externals_abs)/one-jar-boot-<(onejar_version).jar',
+ },
+ },
+ },
+ {
+ 'target_name': 'javacv',
+ 'type': 'none',
+ 'variables': {
+ 'javacv_dir': '<(externals_abs)/javacv-bin',
+ },
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/default-java/include/linux',
+ ],
+ 'variables': {
+ 'classpath': [
+ '<(javacv_dir)/javacv.jar',
+ '<(javacv_dir)/javacpp.jar',
+ '<(javacv_dir)/javacv-linux-x86.jar',
+ ],
+ },
+ },
+ },
+ {
+# TODO(brians) convert this to downloading + building
+ 'target_name': 'libevent',
+ 'type': 'none',
+ 'link_settings': {
+ 'libraries': ['-levent'],
+ },
+ },
+ {
+ 'target_name': 'eigen',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'include_dirs': ['<(externals)/eigen-<(eigen_version)'],
+ },
+ },
+ {
+ 'target_name': 'libjpeg',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'libraries': ['<(externals_abs)/libjpeg/lib/libjpeg.a'],
+ },
+ },
+ {
+ 'target_name': 'gtest',
+ 'type': 'static_library',
+ 'sources': [
+ '<(externals)/gtest-<(gtest_version)/fused-src/gtest/gtest-all.cc',
+ ],
+ 'conditions': [['OS=="crio"', {
+ 'defines': [
+ 'GTEST_HAS_TR1_TUPLE=0',
+ 'GTEST_HAS_STREAM_REDIRECTION=0',
+ 'GTEST_HAS_POSIX_RE=0', # it only has a broken header...
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'GTEST_HAS_TR1_TUPLE=0',
+ 'GTEST_HAS_STREAM_REDIRECTION=0',
+ 'GTEST_HAS_POSIX_RE=0',
+ ],
+ },
+ }, {
+ 'sources': [
+ '<(externals)/gtest-<(gtest_version)/fused-src/gtest/gtest_main.cc',
+ ],
+ }]],
+ 'include_dirs': [
+ '<(externals)/gtest-<(gtest_version)',
+ '<(externals)/gtest-<(gtest_version)/include'
+ ],
+ 'cflags!': ['-Werror'],
+ 'direct_dependent_settings': {
+ 'include_dirs': ['<(externals)/gtest-<(gtest_version)/include'],
+ 'target_conditions': [
+ ['_type=="executable"', {
+ 'product_dir': '<(test_dir)',
+ },
+ ],
+ ],
+ },
+ },
+ {
+ 'target_name': 'ctemplate',
+ 'type': 'none',
+ 'link_settings': {
+ 'libraries': ['<(externals)/ctemplate-<(ctemplate_version)-prefix/lib/libctemplate.a'],
+ },
+ 'direct_dependent_settings': {
+ 'include_dirs': ['<(externals)/ctemplate-<(ctemplate_version)-prefix/include'],
+ },
+ },
+ ],
+}
diff --git a/aos/build/gen_resource_list.rb b/aos/build/gen_resource_list.rb
new file mode 100644
index 0000000..259b438
--- /dev/null
+++ b/aos/build/gen_resource_list.rb
@@ -0,0 +1,36 @@
+outpath = ARGV.shift
+
+outputh = File.new(outpath + '/ResourceList.h', 'w+')
+
+File.open(File.dirname(__FILE__) + '/../atom_code/ipc_lib/resource_list.txt') do |f|
+ outputh.puts <<END
+#ifndef __AOS_RESOURCE_LIST_H_
+#define __AOS_RESOURCE_LIST_H_
+// This file is autogenerated.
+// Edit #{File.expand_path f.path} to change its contents.
+
+#include <stdint.h>
+
+#ifdef __cplusplus // for the c code that just wants to know how long it should be
+namespace aos {
+END
+
+ i = 0
+ f.readlines.each do |l|
+ l = l.chomp
+ outputh.puts "static const uint16_t #{l}(#{i});"
+ i += 1
+ end
+ outputh.puts <<END
+} // namespace aos
+#endif
+
+#define AOS_RESOURCE_NUM #{i}
+
+#endif
+
+END
+end
+
+outputh.close
+
diff --git a/aos/build/java.gypi b/aos/build/java.gypi
new file mode 100644
index 0000000..d832b0a
--- /dev/null
+++ b/aos/build/java.gypi
@@ -0,0 +1,74 @@
+# Include this file in any target that is going to build java files.
+#
+# To use, create a target of the following form:
+# {
+# 'target_name': 'whatever',
+# 'variables': {
+# 'srcdirs': ['.', 'java'],
+# },
+# 'includes': ['path/to/java.gypi'],
+# }
+# See below for more variables.
+# To make any output jars include some loadable modules, set the 'jni_libs'
+# variable in 'direct_dependent_settings'. Making this easier causes lots of
+# recursion issues in gyp.
+# The dependency on these targets also has to be added manually.
+{
+ 'type': 'none',
+ 'variables': {
+# The manifest file for creating the jar.
+ 'manifest%': '/dev/null',
+# Additional jars/directories to add to the classpath when compiling.
+# This target will automatically add itself to this list for any dependents.
+ 'classpath': [],
+# Classes to generate JNI headers for.
+# They will be able to be #included as "jni/package_ClassName.h" by targets
+# that depend on this one.
+ 'gen_headers': [],
+# Like 'srcdirs', except not required to exist at gyp time. However, nothing
+# here will depend on any files in these directories.
+ 'gen_srcdirs': ['/dev/null'],
+# Like 'gen_srcdirs', except all folders that are children of this folder will
+# be used instead.
+ 'gen_srcdir_parents%': [],
+ 'srcdirs': ['/dev/null'],
+ 'jar_dir': '<(PRODUCT_DIR)/jars',
+ 'java_files': '<!(find <(srcdirs) -name *.java)',
+ 'create_jar': '<(AOS)/build/create_jar',
+ 'out_jar': '<(jar_dir)/<(_target_name).jar',
+ 'header_dir': '<(SHARED_INTERMEDIATE_DIR)/jni_headers_<!(pwd | sed s:/:_:g)_<(_target_name)',
+ 'no_rsync': 1,
+ },
+ 'direct_dependent_settings': {
+ 'variables': {
+ 'classpath': ['<(out_jar)'],
+ },
+ 'include_dirs': [
+ '<(header_dir)',
+ ],
+ },
+ 'actions': [
+ {
+ 'action_name': 'run javac',
+ 'message': 'Compiling java code',
+ 'inputs': [
+ '<(create_jar)',
+ '<@(java_files)',
+ '>@(classpath)',
+ '>@(gen_srcdirs)',
+ '>(manifest)',
+ ],
+ 'outputs': [
+ '<(out_jar)',
+ ],
+ 'action': [
+ '<(create_jar)',
+ '<(srcdirs) <(gen_srcdirs)',
+ '<(INTERMEDIATE_DIR)', '>(classpath)',
+ '>(gen_srcdir_parents)',
+ '>(manifest)', '<(out_jar)',
+ '<(header_dir)/jni', '>(gen_headers)',
+ ],
+ },
+ ],
+}
diff --git a/aos/build/jdk_tools_common b/aos/build/jdk_tools_common
new file mode 100644
index 0000000..3ebfc2f
--- /dev/null
+++ b/aos/build/jdk_tools_common
@@ -0,0 +1,13 @@
+# This file gets sourced by all the shell scripts that use the JDK tools.
+# gyp likes quoting some of the input arguments, but nothing else tolerates it,
+# so " are removed from various inputs.
+
+set -e # stop on error
+#set -x # echo everything
+
+TMPDIR=$2
+# ${CLASSPATH} is used by the jdk tools
+EXTRA_CLASSPATH=`echo $3 | tr -d '"' | sed 's/ /:/g'`
+EXTRA_JARS=`echo $3 | tr -d '"'`
+
+mkdir -p ${TMPDIR}
diff --git a/aos/build/mkdirswig b/aos/build/mkdirswig
new file mode 100755
index 0000000..83403e4
--- /dev/null
+++ b/aos/build/mkdirswig
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# Creates the directory specified by the first argument and runs swig with the
+# rest of the arguments.
+mkdir -p $1
+shift
+swig $@
diff --git a/aos/build/onejar.gypi b/aos/build/onejar.gypi
new file mode 100644
index 0000000..6185f02
--- /dev/null
+++ b/aos/build/onejar.gypi
@@ -0,0 +1,53 @@
+# Include this file in any target that should get packaged with OneJAR.
+#
+# To use, create a target of the following form:
+# {
+# 'target_name': 'whatever',
+# 'variables': {
+# 'main_jar': 'something',
+# },
+# 'includes': ['path/to/onejar.gypi'],
+# },
+# See below for more variables.
+{
+ 'type': 'none',
+ 'variables': {
+# The names of loadable_module targets to add to the jar.
+ 'jni_libs': [],
+# Additional jars to add to the output.
+# Named this so that targets from java.gypi will add themselves automatically.
+ 'classpath': [],
+ 'jar_dir': '<(PRODUCT_DIR)/jars',
+ 'create_onejar': '<(AOS)/build/create_onejar',
+ 'out_onejar': '<(rsync_dir)/<(_target_name).jar',
+ 'main_jar_file': '<(jar_dir)/<(main_jar).jar',
+ 'shared_objects': ">!(echo '>(jni_libs)' | sed 's:[^ ]*:<(so_dir)/lib\\0.so:g')",
+ 'no_rsync': 1,
+ },
+ 'dependencies': [
+ '<(EXTERNALS):onejar',
+ ],
+ 'product_dir': '<(PRODUCT_DIR)',
+ 'actions': [
+ {
+ 'action_name': 'create onejar',
+ 'message': 'Creating OneJAR jar',
+ 'inputs': [
+ '<(create_onejar)',
+ '>@(classpath)',
+ '<(main_jar_file)',
+ '>@(shared_objects)',
+ ],
+ 'outputs': [
+ '<(out_onejar)',
+ ],
+ 'action': [
+ '<(create_onejar)',
+ '<(main_jar_file)',
+ '<(INTERMEDIATE_DIR)', '>(classpath)',
+ '<(out_onejar)', '>(onejar_jar)',
+ '>(shared_objects)',
+ ],
+ },
+ ],
+}
diff --git a/aos/build/parser.rb b/aos/build/parser.rb
new file mode 100644
index 0000000..6163129
--- /dev/null
+++ b/aos/build/parser.rb
@@ -0,0 +1,556 @@
+require 'digest'
+require 'fileutils'
+
+def javaify name
+ name = name.dup
+ name.gsub! /(\w)_(\w)/ do
+ $1 + $2.upcase
+ end
+ name.gsub /^\w/ do |char|
+ char.downcase
+ end
+end
+
+module Contents
+ class SyntaxError < Exception
+ end
+ class Tokenizer
+ def initialize file
+ @file = file
+ @token = ""
+ @lineno = 0
+ end
+ def filename
+ @file.path
+ end
+ def pop_char
+ if char = @hold_char
+ @hold_char = nil
+ return char
+ end
+ return @file.read(1)
+ end
+ def unpop_char char
+ @hold_char = char
+ end
+ def clear_comment
+ @hold_char = nil
+ @file.gets
+ @lineno += 1
+ end
+ def syntax_error error
+ filename = File.basename(@file.path)
+ line = @lineno + 1
+ raise SyntaxError, error + "\n from #{line} of #{filename}", caller
+ end
+ def item_missing item
+ syntax_error "expected \"#{item}\"! you missing something!?"
+ end
+ def peek_token
+ @peek_token = next_token
+ end
+ def next_token
+ if token = @peek_token
+ @peek_token = nil
+ return token
+ end
+ token = @token
+ while char = pop_char
+ if char == "\n"
+ @lineno += 1
+ end
+ if char == "/"
+ if pop_char == "/"
+ clear_comment
+ else
+ syntax_error("unexpected #{char.inspect}")
+ end
+ elsif char =~ /[\s\r\n]/
+ if token.length > 0
+ @token = ""
+ return token
+ end
+ elsif char =~ /[;\{\}]/
+ if token.length > 0
+ unpop_char char
+ @token = ""
+ return token
+ end
+ return(char)
+ elsif token.length > 0 && char =~ /[\w:]/
+ token += char
+ elsif char =~ /[a-zA-Z0-9]/
+ token = char
+ else
+ syntax_error("unexpected #{char.inspect}")
+ end
+ end
+ rescue EOFError
+ end
+ def self.is_string token
+ token =~ /[a-zA-Z]\w*/
+ end
+ def self.is_number token
+ token =~ /[0-9]*/
+ end
+ end
+
+ class Struct
+ class StructField
+ def initialize
+ @members = [] # array of strings
+ end
+ def parse tokenizer
+ while true
+ token = tokenizer.next_token
+ if Tokenizer.is_string(token)
+ @members.push token
+ elsif token == ";" || token == "\n"
+ if @members.length > 0
+ return @members
+ else
+ return nil
+ end
+ else
+ tokenizer.syntax_error("expected member name in struct!")
+ end
+ end
+ end
+ def self.parse *args
+ self.new.parse *args
+ end
+ def use members
+ members
+ end
+ def self.use *args
+ self.new.use *args
+ end
+ def to_s
+ @members.join " "
+ end
+ end
+
+ def parse tokenizer, parse_name = true
+ if parse_name
+ token = tokenizer.next_token
+ if Tokenizer.is_string(token)
+ @name_raw = token
+ else
+ tokenizer.syntax_error("expected struct name!")
+ end
+ else
+ @name_raw = nil
+ @name_data = tokenizer.filename
+ end
+ token = tokenizer.next_token
+ tokenizer.syntax_error("expected '{', got '#{token}'") if(token != "{")
+ while token != "}"
+ token = tokenizer.peek_token
+ if token != "}"
+ field = StructField.parse(tokenizer)
+ @fields.push(field) if(field)
+ end
+ end
+ if tokenizer.next_token == "}"
+ return self
+ else
+ tokenizer.syntax_error("wahh; call parker. #{__LINE__}")
+ end
+ end
+ def self.parse *args
+ self.new.parse *args
+ end
+
+ def use fields, name_data
+ @name_raw = nil
+ @name_data = name_data
+ fields.each do |field|
+ @fields.push(StructField.use field.split(' '))
+ end
+ self
+ end
+ def self.use *args
+ self.new.use *args
+ end
+
+ def name
+ @name_raw || gen_name
+ end
+ def gen_name
+ unless @generated_name
+ @generated_name = 'a' + Digest::SHA1.hexdigest(@fields.join('') + $namespace + @name_data)
+ end
+ @generated_name
+ end
+
+ def initialize
+ @fields = [] # array of arrays of strings
+ @hidden_fields = []
+ end
+ def upcase_name
+ name.gsub(/^[a-z]|_[a-z]/) do |v|
+ v[-1].chr.upcase
+ end
+ end
+ def join_fields array
+ (array.collect { |a|
+ " #{a.join(" ")};"
+ }).join("\n")
+ end
+ def fields
+ join_fields @fields
+ end
+ def hidden_fields
+ join_fields @hidden_fields
+ end
+ def add_hidden_field k, v
+ @hidden_fields.push [k, v]
+ end
+ def params
+ (@fields.collect do |a|
+ a.join(" ")
+ end).join(', ')
+ end
+ def copy_params_into varname, decl = true
+ (decl ? "#{name} #{varname};\n" : '') + (@fields.collect do |a|
+ "#{varname}.#{a[-1]} = #{a[-1]};"
+ end).join("\n")
+ end
+ def params_from name
+ (@fields.collect do |a|
+ name + '.' + a[-1]
+ end).join(', ')
+ end
+ def builder_name aos_namespace = true, this_namespace = true
+ (aos_namespace ? "aos::" : '') + "QueueBuilder<#{this_namespace ? $namespace + '::' : ''}#{name}>"
+ end
+ def java_builder
+ name + 'Builder'
+ end
+ def builder_defs name
+ (@fields.collect do |field|
+ " inline #{name} &#{field[-1]}" +
+ "(#{field[0...-1].join(" ")} in) " +
+ "{ holder_.View().#{field[-1]} = in; return *this; }"
+ end).join "\n"
+ end
+ def swig_builder_defs name
+ (@fields.collect do |field|
+ " %rename(#{javaify field[-1]}) #{field[-1]};\n" +
+ " #{name} &#{field[-1]}" +
+ "(#{field[0...-1].join(" ")} #{field[-1]});"
+ end).join "\n"
+ end
+ def zero name
+ (@fields.collect do |field|
+ " new (&#{name}.#{field[-1]}) #{field[0...-1].join ' '}();"
+ end).join("\n")
+ end
+ def size
+ (@fields.collect do |field|
+ "sizeof(#{$namespace}::#{name}::#{field[-1]})"
+ end.push('0')).join(' + ')
+ end
+ def get_format(field)
+ case(field[0...-1])
+ when ['int']
+ r = '%d'
+ when ['float'], ['double']
+ r = '%f'
+ when ['bool']
+ r = '%s'
+ when ['uint8_t']
+ r = '%hhu'
+ when ['uint16_t']
+ r = '%d'
+ when ['struct', 'timespec']
+ r = '%jdsec,%ldnsec'
+ else
+ return 'generator_error'
+ end
+ return field[-1] + ': ' + r
+ end
+ def to_printf(name, field)
+ case(field[0...-1])
+ when ['bool']
+ return name + '.' + field[-1] + ' ? "true" : "false"'
+ when ['uint16_t']
+ return "static_cast<int>(#{name}.#{field[-1]})"
+ when ['struct', 'timespec']
+ return "#{name}.#{field[-1]}.tv_sec, #{name}.#{field[-1]}.tv_nsec"
+ else
+ return name + '.' + field[-1]
+ end
+ end
+ def netop name, buffer
+ offset = '0'
+ (@fields.collect do |field|
+ # block |var_pointer, output_pointer|
+ val = yield "&#{name}.#{field[-1]}", "&#{buffer}[#{offset}]"
+ offset += " + sizeof(#{name}.#{field[-1]})"
+ ' ' + val
+ end).join("\n") + "\n " +
+ "static_assert(#{offset} == #{size}, \"code generator issues\");"
+ end
+ def hton name, output
+ netop(name, output) do |var, output|
+ "to_network(#{var}, #{output});"
+ end
+ end
+ def ntoh input, name
+ netop(name, input) do |var, input|
+ "to_host(#{input}, #{var});"
+ end
+ end
+ def swig_writer
+ <<END
+struct #{name} {
+#{(@fields.collect { |a|
+ " %rename(#{javaify a[-1]}) #{a[-1]};"
+}).join("\n")}
+#{self.fields}
+ %extend {
+ const char *toString() {
+ return aos::TypeOperator<#{$namespace}::#{name}>::Print(*$self);
+ }
+ }
+ private:
+ #{name}();
+};
+} // namespace #{$namespace}
+namespace aos {
+%typemap(jstype) #{builder_name false}& "#{java_builder}"
+%typemap(javaout) #{builder_name false}& {
+ $jnicall;
+ return this;
+ }
+template <> class #{builder_name false} {
+ private:
+ #{builder_name false}();
+ public:
+ inline bool Send();
+ %rename(#{javaify 'Send'}) Send;
+#{swig_builder_defs builder_name(false)}
+};
+%template(#{java_builder}) #{builder_name false};
+%typemap(javaout) #{builder_name false}& {
+ return new #{java_builder}($jnicall, false);
+ }
+} // namespace aos
+namespace #{$namespace} {
+END
+ end
+ def writer
+ <<END
+struct #{name} {
+#{self.fields}
+#{self.hidden_fields}
+};
+} // namespace #{$namespace}
+namespace aos {
+template <> class TypeOperator<#{$namespace}::#{name}> {
+ public:
+ static void Zero(#{$namespace}::#{name} &inst) {
+ (void)inst;
+#{zero 'inst'}
+ }
+ static void NToH(const char *input, #{$namespace}::#{name} &inst) {
+ (void)input;
+ (void)inst;
+#{ntoh 'input', 'inst'}
+ }
+ static void HToN(const #{$namespace}::#{name} &inst, char *output) {
+ (void)inst;
+ (void)output;
+#{hton 'inst', 'output'}
+ }
+ static inline size_t Size() { return #{size}; }
+ static const char *Print(const #{$namespace}::#{name} &inst) {
+#{@fields.empty? ? <<EMPTYEND : <<NOTEMPTYEND}
+ (void)inst;
+ return "";
+EMPTYEND
+ static char buf[1024];
+ if (snprintf(buf, sizeof(buf), "#{@fields.collect do |field|
+ get_format(field)
+ end.join(', ')}", #{@fields.collect do |field|
+ to_printf('inst', field)
+ end.join(', ')}) >= static_cast<ssize_t>(sizeof(buf))) {
+ LOG(WARNING, "#{name}'s buffer was too small\\n");
+ buf[sizeof(buf) - 1] = '\\0';
+ }
+ return buf;
+NOTEMPTYEND
+ }
+};
+template <> class #{builder_name false} {
+ private:
+ aos::QueueHolder<#{$namespace}::#{name}> &holder_;
+ public:
+ #{builder_name false}(aos::QueueHolder<#{$namespace}::#{name}> &holder) : holder_(holder) {}
+ inline bool Send() { return holder_.Send(); }
+ inline const char *Print() const { return holder_.Print(); }
+#{builder_defs builder_name(false)}
+};
+} // namespace aos
+namespace #{$namespace} {
+END
+ end
+ def to_s
+ return <<END
+#{name}: #{(@fields.collect {|n| n.join(" ") }).join("\n\t")}
+END
+ end
+ end
+
+ class SimpleField
+ def initialize check_function = :is_string
+ @check_function = check_function
+ @name = nil
+ end
+ def parse tokenizer
+ token = tokenizer.next_token
+ if Tokenizer.__send__ @check_function, token
+ @name = token
+ else
+ tokenizer.syntax_error('expected value!')
+ end
+ if tokenizer.next_token == ';'
+ @name
+ else
+ tokenizer.syntax_error('expected ";"!')
+ end
+ end
+ def self.parse tokenizer
+ self.new.parse tokenizer
+ end
+ end
+ class NameField < SimpleField
+ end
+
+ class OutputFile
+ def initialize namespace, filename, topdir, outpath
+ @namespace = namespace
+ $namespace = namespace
+ @base = filename.gsub(/\.\w*$/, "").gsub(/^.*\//, '')
+ @topdir = topdir
+ @filebase = outpath + @base
+ @filename = filename
+ FileUtils.mkdir_p(outpath)
+
+ fillin_initials if respond_to? :fillin_initials
+ parse filename
+ fillin_defaults if respond_to? :fillin_defaults
+ self
+ rescue SyntaxError => e
+ puts e
+ exit 1
+ end
+ def filename type
+ case type
+ when 'h'
+ @filebase + '.q.h'
+ when 'cc'
+ @filebase + '.q.cc'
+ when 'main'
+ @filebase + '_main.cc'
+ when 'swig'
+ @filebase + '.swg'
+ when 'java_dir'
+ @filebase + '_java/'
+ when 'java_wrap'
+ @filebase + '_java_wrap.cc'
+ else
+ throw SyntaxError, "unknown filetype '#{type}'"
+ end
+ end
+ def parse filename
+ file = File.open filename
+ tokenizer = Tokenizer.new file
+ while token = tokenizer.next_token
+ if !token || token.gsub('\s', '').empty?
+ elsif token == ';'
+ else
+ error = catch :syntax_error do
+ case token
+ when 'namespace'
+ $namespace = NameField.parse tokenizer
+ else
+ parse_token token, tokenizer
+ end
+ nil
+ end
+ if error
+ tokenizer.syntax_error error.to_s
+ raise error
+ end
+ end
+ end
+
+ check_format tokenizer
+ end
+ def call_swig
+ output_dir = filename('java_dir') + $namespace
+ FileUtils.mkdir_p(output_dir)
+ if (!system('swig', '-c++', '-Wall', '-Wextra', '-java',
+ '-package', $namespace, "-I#{@topdir}",
+ '-o', filename('java_wrap'),
+ '-outdir', output_dir, filename('swig')))
+ exit $?.to_i
+ end
+ end
+
+ def queue_holder_accessors suffix, var, type, force_timing = nil
+<<END
+ inline bool Get#{suffix}(#{force_timing ? '' : 'bool check_time'}) aos_check_rv { return #{var}.Get(#{force_timing || 'check_time'}); }
+ inline #{type} &View#{suffix}() { return #{var}.View(); }
+ inline void Clear#{suffix}() { #{var}.Clear(); }
+ inline bool Send#{suffix}() { return #{var}.Send(); }
+ inline const char *Print#{suffix}() { return #{var}.Print(); }
+ inline aos::QueueBuilder<#{type}> &#{suffix || 'Builder'}() { return #{var}.Builder(); }
+END
+ end
+ def queue_holder_accessors_swig suffix, var, type, force_timing = nil
+<<END
+ %rename(#{javaify "Get#{suffix}"}) Get#{suffix};
+ bool Get#{suffix}(#{force_timing ? '' : 'bool check_time'});
+ %rename(#{javaify "View#{suffix}"}) View#{suffix};
+ #{type} &View#{suffix}();
+ %rename(#{javaify "Clear#{suffix}"}) Clear#{suffix};
+ void Clear#{suffix}();
+ %rename(#{javaify "Send#{suffix}"}) Send#{suffix};
+ bool Send#{suffix}();
+ %rename(#{javaify suffix || 'Builder'}) #{suffix || 'Builder'};
+ aos::QueueBuilder<#{type}> &#{suffix || 'Builder'}();
+END
+ end
+ end
+end
+
+def write_file_out
+ if ARGV.length < 3
+ puts 'Error: at least 3 arguments required!!!'
+ exit 1
+ end
+ file = Contents::OutputFile.new ARGV.shift,
+ File.expand_path(ARGV.shift),
+ ARGV.shift,
+ File.expand_path(ARGV.shift) + '/'
+ while !ARGV.empty?
+ case type = ARGV.shift
+ when 'cpp'
+ file.write_cpp
+ when 'header'
+ file.write_header
+ when 'main'
+ file.write_main
+ when 'swig'
+ file.write_swig
+ file.call_swig
+ else
+ puts "Error: unknown output type '#{type}'"
+ exit 1
+ end
+ end
+end
+
diff --git a/aos/build/queues.gypi b/aos/build/queues.gypi
new file mode 100644
index 0000000..30fe7cd
--- /dev/null
+++ b/aos/build/queues.gypi
@@ -0,0 +1,123 @@
+# Include this file in any target that needs to use files generated from queue
+# etc. definitions.
+#
+# To use, create a target of the following form:
+# {
+# 'target_name': 'my_queues',
+# 'type': 'static_library', # or any other type that can handle .cc files
+# 'sources': [
+# 'aos/example/Queue.q',
+# 'aos/example/ControlLoop.q',
+# ],
+# 'variables': {
+# 'header_path': 'aos/example',
+# },
+# 'includes': ['path/to/queues.gypi'],
+# },
+# Code that depends on this target will be able to #include
+# "aos/example/Queue.q.h" and "aos/example/ControlLoop.q.h".
+#
+# using <http://src.chromium.org/svn/trunk/src/build/protoc.gypi> as an
+# example of how this should work
+{
+ 'variables': {
+ #'header_path': '>!(python -c "import os.path; print os.path.relpath(\'<(RULE_INPUT_PATH)\', \'<(DEPTH)\')")',
+ 'prefix_dir': '<(SHARED_INTERMEDIATE_DIR)/<!(echo <(header_path) | sed "s/[^A-Za-z0-9]/_/g")',
+ 'out_dir': '<(prefix_dir)/<(_target_name)/<(header_path)',
+ 'gen_namespace%': '>!(echo >(header_path) | sed "s:\([^/]*\).*:\\1:g")',
+ 'output_h': '<(out_dir)/<(RULE_INPUT_ROOT).q.h',
+ 'output_cc': '<(out_dir)/<(RULE_INPUT_ROOT).q.cc',
+ 'output_main': '<(out_dir)/<(RULE_INPUT_ROOT)_main.cc',
+ 'output_swg': '<(out_dir)/<(RULE_INPUT_ROOT).q.swig',
+ 'output_java_wrap': '<(out_dir)/<(RULE_INPUT_ROOT)_java_wrap.cc',
+ 'java_dir': '<(out_dir)/<(RULE_INPUT_ROOT).q_java',
+ 'no_rsync': 1,
+ },
+ 'rules': [
+ {
+ 'variables': {
+ 'script': '<(AOS)/build/queues/compiler.rb',
+ },
+ 'rule_name': 'genqueue',
+ 'extension': 'q',
+ 'outputs': [
+ '<(output_h)',
+ '<(output_cc)',
+ ],
+ 'conditions': [
+ ['OS=="crio"', {
+ 'outputs': [
+ # cRIO doesn't do swig for a good reason.
+ ]
+ },{
+ 'outputs': [
+ '<(output_swg)',
+ '<(output_java_wrap)',
+ '<(java_dir)',
+ ]
+ }]
+ ],
+ 'inputs': [
+ '<(script)',
+ '<!@(find <(AOS)/build/queues/ -name *.rb)',
+ '<(AOS)/common/queue.h',
+ '<(AOS)/common/time.h',
+ ],
+ 'action': ['ruby', '<(script)',
+ '--swig',
+ '--swigccout', '<(output_java_wrap)',
+ '-I', '<(DEPTH)',
+ '<(RULE_INPUT_PATH)',
+ '-cpp_out',
+ '<(header_path)',
+ '-cpp_base',
+ '<(prefix_dir)/<(_target_name)'],
+ 'message': 'Generating C++ code from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).q',
+ 'process_outputs_as_sources': 1,
+ },
+ {
+ 'variables': {
+ 'script': '<(AOS)/build/act_builder.rb',
+ },
+ 'rule_name': 'genact',
+ 'extension': 'act',
+ 'outputs': [
+ '<(output_h)',
+ '<(output_cc)',
+ '<(output_main)',
+ ],
+ 'inputs': [
+ '<(script)',
+ ],
+ 'action': ['ruby', '<(script)',
+ '<(gen_namespace)',
+ '<(RULE_INPUT_PATH)',
+ '<(DEPTH)',
+ '<(out_dir)', 'header', 'cpp', 'main'],
+ #'message': 'Generating C++ code from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).act',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ 'cflags': [
+# For the swig-generated C++ code.
+ '-fno-strict-aliasing',
+ '-Wno-cast-qual',
+ ],
+ 'include_dirs': [
+ '/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/default-java/include/linux',
+ '<(prefix_dir)/<(_target_name)',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(prefix_dir)/<(_target_name)',
+ ],
+ 'variables': {
+ 'gen_srcdir_parents': ['<(out_dir)'],
+ },
+ },
+ 'dependencies': [
+ '<(AOS)/build/aos.gyp:aos_internal_nolib',
+ ],
+ 'hard_dependency': 1,
+}
diff --git a/aos/build/queues/compiler.rb b/aos/build/queues/compiler.rb
new file mode 100644
index 0000000..aef5cbf
--- /dev/null
+++ b/aos/build/queues/compiler.rb
@@ -0,0 +1,151 @@
+["tokenizer.rb","q_file.rb","queue_group.rb","queue.rb","namespaces.rb",
+"interface.rb","errors.rb"].each do |name|
+ require File.dirname(__FILE__) + "/objects/" + name
+end
+["standard_types.rb","auto_gen.rb","file_pair_types.rb",
+"dep_file_pair.rb","swig.rb"].each do |name|
+ require File.dirname(__FILE__) + "/cpp_pretty_print/" + name
+end
+["q_file.rb","message_dec.rb","queue_dec.rb"].each do |name|
+ require File.dirname(__FILE__) + "/output/" + name
+end
+require "fileutils"
+require "pathname"
+
+def parse_args(globals,args)
+ i = 0
+ $swig = false
+ $swigccout_path = ""
+ while(i < args.length)
+ if(args[i] == "-I")
+ args.delete_at(i)
+ if(!args[i])
+ $stderr.puts "hey! -I is followed by nothing."
+ $stderr.puts "\tnot a supported usage..."
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+ path = args.delete_at(i)
+ globals.add_path(path)
+ elsif(args[i] == "--swigccout")
+ args.delete_at(i)
+ $swigccout_path = args.delete_at(i)
+ elsif(args[i] == "-cpp_out")
+ args.delete_at(i)
+ path = args.delete_at(i)
+ if(path =~ /\./)
+ $stderr.puts "hey! path #{path} has a \".\" char which is "
+ $stderr.puts "\tnot a supported usage..."
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ elsif(!path)
+ $stderr.puts "hey! No cpp_out path provided."
+ $stderr.puts "\tumm, you could try -cpp_out \"\""
+ $stderr.puts "\tThat might do the trick"
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+ $cpp_out = path.split(/\\|\//)
+ elsif(args[i] == "--swig")
+ $swig = true
+ args.delete_at(i)
+ elsif(args[i] == "-cpp_base")
+ args.delete_at(i)
+ path = args.delete_at(i)
+ $cpp_base = File.expand_path(path)
+ if(!File.exists?($cpp_base))
+ $stderr.puts "output directory #{$cpp_base.inspect} does not exist."
+ $stderr.puts "\tI'm not going to make that! sheesh, who do you think I am?"
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+ elsif(args[i] =~ /^-/)
+ $stderr.puts "hey! unknown argument #{args[i]}."
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ else
+ i += 1
+ end
+ end
+ if(!$cpp_base)
+ $stderr.puts "hey! missing -cpp_base argument."
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+ if(!$cpp_out)
+ $stderr.puts "hey! missing -cpp_out argument."
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+end
+def build(filename,globals_template)
+ globals = Globals.new()
+ globals_template.paths.each do |path|
+ globals.add_path(path)
+ end
+ filename = File.expand_path(filename)
+ q_file = QFile.parse(filename)
+ output_file = q_file.q_eval(globals)
+ q_filename = File.basename(filename)
+ rel_path = ($cpp_out + [q_filename]).join("/")
+
+ FileUtils.mkdir_p(Pathname.new($cpp_base) + $cpp_out.join("/"))
+
+ cpp_tree = output_file.make_cpp_tree(rel_path)
+
+ h_file_path = $cpp_base + "/" + rel_path + ".h"
+ cc_file_path = $cpp_base + "/" + rel_path + ".cc"
+ swig_file_path = $cpp_base + "/" + rel_path + ".swig"
+ java_directory = $cpp_base + "/" + rel_path + "_java/"
+ cpp_tree.add_cc_include((rel_path + ".h").inspect)
+ cpp_tree.add_cc_include("aos/common/byteorder.h".inspect)
+ cpp_tree.add_cc_include("aos/common/inttypes.h".inspect)
+ cpp_tree.add_cc_using("::aos::to_network")
+ cpp_tree.add_cc_using("::aos::to_host")
+ cpp_tree.add_swig_header_include("aos/common/queue.h".inspect)
+ cpp_tree.add_swig_body_include("aos/atom_code/queue-tmpl.h".inspect)
+ cpp_tree.add_swig_header_include("aos/common/time.h".inspect)
+ cpp_tree.add_swig_include((rel_path + ".h").inspect)
+
+ header_file = File.open(h_file_path,"w+")
+ cc_file = File.open(cc_file_path,"w+")
+ cpp_tree.write_header_file($cpp_base,header_file)
+ cpp_tree.write_cc_file($cpp_base,cc_file)
+ cc_file.close()
+ header_file.close()
+ if ($swig)
+ swig_file = File.open(swig_file_path,"w+")
+ cpp_tree.write_swig_file($cpp_base,swig_file,q_filename)
+ swig_file.close()
+ namespace = q_file.namespace.get_name()[1..-1]
+ FileUtils.mkdir_p(java_directory)
+ includes = globals.paths.collect { |a| "-I#{a}" }
+
+ if (!system('/usr/bin/swig', *(includes + ['-I' + $cpp_base + '/',
+ '-package', namespace,
+ '-outdir', java_directory,
+ '-o', $swigccout_path,
+ '-c++', '-Wall', '-Wextra', '-java', swig_file_path])))
+ puts "Swig failed."
+ exit -1
+ end
+ end
+end
+begin
+ args = ARGV.dup
+ globals = Globals.new()
+ parse_args(globals,args)
+ if(args.length == 0)
+ $stderr.puts "hey! you want me to do something,"
+ $stderr.puts "\tbut you gave me no q files to build!"
+ $stderr.puts "\tWot. Wot."
+ exit!(-1)
+ end
+ args.each do |filename|
+ build(filename,globals)
+ end
+ exit(0)
+rescue QError => e
+ $stderr.print(e.to_s)
+ exit!(-1)
+end
diff --git a/aos/build/queues/cpp_pretty_print/auto_gen.rb b/aos/build/queues/cpp_pretty_print/auto_gen.rb
new file mode 100644
index 0000000..633c7c0
--- /dev/null
+++ b/aos/build/queues/cpp_pretty_print/auto_gen.rb
@@ -0,0 +1,282 @@
+module CPP
+end
+class CPP::Comment
+ def initialize(text)
+ @text = text
+ end
+ def pp(state)
+ state.needs_semi = false
+ if(@text.include?("\n"))
+ state.print("/* #{@text} */")
+ else
+ state.print("// #{@text}")
+ end
+ end
+end
+class CPP::TODO < CPP::Comment
+ def initialize(owner,text)
+ @text = "TODO(#{owner}): #{text}"
+ end
+end
+class CPP::MemberFunc
+ class ForwardDec
+ def initialize(func) ; @func = func ; end
+ def pp(state) ; @func.pp_forward_dec(state) ; end
+ end
+ attr_accessor :args,:suite,:return_type,:name,:pre_func_types,:const,:static,:virtual
+ def initialize(type_class,return_type,name)
+ @type_class = type_class
+ @return_type = return_type
+ @name = name
+ @const = false
+ @static = false
+ @virtual = false
+ @args = CPP::Args.new()
+ @suite = CPP::Suite.new()
+ end
+ attr_accessor :inline
+ def forward_dec() ; ForwardDec.new(self) ; end
+ def pp_forward_dec(state)
+ return self.pp_inline(state) if(@inline)
+ if (@static)
+ state.print("static ")
+ elsif (@virtual)
+ state.print("virtual ")
+ end
+ state.print("#{@return_type} #{@pre_func_types}#{@name}(")
+ state.pp(@args)
+ state.print(")")
+ if (@const)
+ state.print(" const")
+ end
+ end
+ def pp_inline(state)
+ if (@static)
+ state.print("static ")
+ elsif (@virtual)
+ state.print("virtual ")
+ end
+ state.print("#{@return_type} #{@pre_func_types}#{@name}(")
+ state.pp(@args)
+ state.print(") ")
+ if (@const)
+ state.print(" const")
+ end
+ @suite.pp_one_line(state)
+ end
+ def pp(state)
+ return if(@inline)
+ state.print("#{@return_type} #{@pre_func_types}#{@type_class.chop_method_prefix}#{@name}(")
+ state.pp(@args)
+ state.print(") ")
+ if (@const)
+ state.print("const ")
+ end
+ state.pp(@suite)
+ state.v_pad(2)
+ end
+ def pp_pre_swig_file(state)
+ end
+ def pp_post_swig_file(state)
+ end
+ alias_method :pp_header_file, :pp_forward_dec
+ alias_method :pp_cc_file, :pp
+
+end
+class CPP::Constructor
+ class ForwardDec
+ def initialize(func) ; @func = func ; end
+ def pp(state) ; @func.pp_forward_dec(state) ; end
+ end
+ attr_accessor :args,:suite,:return_type,:name
+ def initialize(type_class)
+ @type_class = type_class
+ @args = CPP::Args.new()
+ @suite = CPP::Suite.new()
+ @var_cons = CPP::Args.new()
+ end
+ def forward_dec() ; ForwardDec.new(self) ; end
+ def add_cons(*args)
+ @var_cons.push(CPP::FuncCall.build(*args))
+ end
+ def pp_forward_dec(state)
+ state.print("#{@type_class.name}(")
+ state.pp(@args)
+ state.print(")")
+ end
+ def pp_inline(state)
+ pp(state,false)
+ end
+ def pp(state,prefix = true)
+ state.needs_semi = false
+ state.print(@type_class.chop_method_prefix) if(prefix)
+ state.print("#{@type_class.name}(")
+ state.pp(@args)
+ if(@var_cons.length >= 1)
+ state.print(")")
+ state.endline()
+ state.indent += 4
+ state.print(": ")
+ state.pp(@var_cons)
+ state.indent -= 4
+ state.print(" ")
+ else
+ state.print(") ")
+ end
+ state.pp(@suite)
+ state.v_pad(2)
+ end
+ alias_method :pp_header_file, :pp_forward_dec
+ alias_method :pp_cc_file, :pp
+end
+class CPP::Destructor
+ class ForwardDec
+ def initialize(func) ; @func = func ; end
+ def pp(state) ; @func.pp_forward_dec(state) ; end
+ end
+ attr_accessor :args,:suite,:return_type,:name
+ def initialize(type_class)
+ @type_class = type_class
+ @args = CPP::Args.new()
+ @suite = CPP::Suite.new()
+ end
+ def forward_dec() ; ForwardDec.new(self) ; end
+ def pp_forward_dec(state)
+ state.print("~#{@type_class.name}(")
+ state.pp(@args)
+ state.print(")")
+ end
+ def pp(state)
+ state.print("#{@type_class.chop_method_prefix}~#{@type_class.name}(")
+ state.pp(@args)
+ state.print(") ")
+ state.pp(@suite)
+ state.v_pad(2)
+ end
+ alias_method :pp_header_file, :pp_forward_dec
+ alias_method :pp_cc_file, :pp
+end
+class CPP::Include
+ attr_accessor :filename
+ def initialize(filename)
+ @filename = filename
+ end
+ def pp(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#include #{@filename}")
+ state.endline()
+ end
+end
+class CPP::IncludeGuard
+ attr_accessor :name,:suite
+ def initialize(suite = CPP::Suite.new())
+ @suite = suite
+ end
+ def self.rand_name(len = 40)
+ str = ""
+ len.times { str += ((rand(26) + ?A).chr)}
+ return str
+ end
+ def pp(state)
+ @name ||= IncludeGuard.rand_name
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#ifndef #{@name}")
+ state.endline()
+ state.suppress_indent()
+ state.print("#define #{@name}")
+ state.endline()
+ if(@suite.respond_to?(:pp_no_braces))
+ @suite.pp_no_braces(state)
+ else
+ state.pp(@suite)
+ end
+ state.endline()
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#endif // #{@name}")
+ state.endline()
+ end
+end
+class CPP::IfnDef
+ attr_accessor :name,:suite
+ def initialize(suite = CPP::Suite.new())
+ @suite = suite
+ end
+ def pp(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#ifndef #{@name}")
+ state.endline()
+ if(@suite.respond_to?(:pp_no_braces))
+ @suite.pp_no_braces(state)
+ else
+ state.pp(@suite)
+ end
+ state.endline()
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#endif // #{@name}")
+ state.endline()
+ end
+end
+class CPP::PreprocessorIf
+ attr_accessor :name,:suite
+ def initialize(ifsuite, elsesuite)
+ @ifsuite = ifsuite
+ @elsesuite = elsesuite
+ end
+ def write_if(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#if #{@name}")
+ state.endline()
+ end
+ def write_else(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#else // #{@name}")
+ state.endline()
+ end
+ def write_endif(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("#endif // #{@name}")
+ state.endline()
+ end
+ def pp_inline(state)
+ self.write_if(state)
+ @ifsuite.pp_inline(state)
+ if(@elsesuite != nil)
+ self.write_else(state)
+ @elsesuite.pp_inline(state)
+ end
+ self.write_endif(state)
+ end
+ def pp(state)
+ self.write_if(state)
+ if(@ifsuite.respond_to?(:pp_no_braces))
+ @ifsuite.pp_no_braces(state)
+ else
+ state.pp(@ifsuite)
+ end
+ if(@elsesuite != nil)
+ self.write_else(state)
+ if(@elsesuite.respond_to?(:pp_no_braces))
+ @elsesuite.pp_no_braces(state)
+ else
+ state.pp(@elsesuite)
+ end
+ end
+ self.write_endif(state)
+ end
+end
+class CPP::Using
+ def initialize(using)
+ @using = using
+ end
+ def pp(state)
+ state.print("using #{@using}")
+ end
+end
diff --git a/aos/build/queues/cpp_pretty_print/dep_file_pair.rb b/aos/build/queues/cpp_pretty_print/dep_file_pair.rb
new file mode 100644
index 0000000..571d9e0
--- /dev/null
+++ b/aos/build/queues/cpp_pretty_print/dep_file_pair.rb
@@ -0,0 +1,617 @@
+class GroupElement
+ def add_group_dep(group_dep)
+ @group_dep = group_dep
+ end
+ def adjust_group(state,old_group)
+ if(@group_dep != old_group)
+ @group_dep.adjust_from(state,old_group)
+ end
+ return @group_dep
+ end
+end
+class DepMask < GroupElement
+ def initialize(elem)
+ @elem = elem
+ @deps = []
+ end
+ def add_dep(dep)
+ @deps << dep
+ self
+ end
+ def method_missing(method,*args,&blk)
+ @elem.send(method,*args,&blk)
+ end
+ alias_method :old_respond_to, :respond_to?
+ def respond_to?(method)
+ old_respond_to(method) || @elem.respond_to?(method)
+ end
+end
+
+class MemberElementHeader < GroupElement
+ def initialize(elem)
+ @elem = elem
+ end
+ def pp(state)
+ if(@elem.respond_to?(:pp_header_file))
+ @elem.pp_header_file(state)
+ else
+ state.pp(@elem)
+ end
+ end
+ def self.check(plan,elem)
+ plan.push(self.new(elem))
+ end
+end
+class MemberElementInline < GroupElement
+ def initialize(elem)
+ @elem = elem
+ end
+ def pp(state)
+ if(@elem.respond_to?(:pp_inline))
+ @elem.pp_inline(state)
+ else
+ state.pp(@elem)
+ end
+ end
+end
+class MemberElementPreSWIG < GroupElement
+ def initialize(elem)
+ @elem = elem
+ end
+ def pp(state)
+ if(@elem.respond_to?(:pp_pre_swig_file))
+ @elem.pp_pre_swig_file(state)
+ else
+ state.pp(@elem)
+ end
+ end
+ def self.check(plan,elem)
+ plan.push(self.new(elem)) if(elem.respond_to?(:pp_pre_swig_file))
+ end
+end
+class MemberElementPostSWIG < GroupElement
+ def initialize(elem)
+ @elem = elem
+ end
+ def pp(state)
+ if(@elem.respond_to?(:pp_post_swig_file))
+ @elem.pp_post_swig_file(state)
+ else
+ state.pp(@elem)
+ end
+ end
+ def self.check(plan,elem)
+ plan.push(self.new(elem)) if(elem.respond_to?(:pp_post_swig_file))
+ end
+end
+class MemberElementCC < GroupElement
+ attr_accessor :pp_override
+ def initialize(elem)
+ @elem = elem
+ end
+ def pp(state)
+ return state.pp(@elem) if(@pp_override)
+ @elem.pp_cc_file(state)
+ end
+ def self.check(plan,elem)
+ plan.push(self.new(elem)) if(elem.respond_to?(:pp_cc_file))
+ end
+end
+class ImplicitName
+ attr_accessor :parent
+ def initialize(name,parent)
+ @name = name
+ @parent = parent
+ end
+ def close(state)
+ state.endline()
+ state.needs_semi = false
+ state.print("} // namespace #{@name}\n")
+ end
+ def name()
+ if(@parent)
+ return @parent.name + "." + @name
+ else
+ return "." + @name
+ end
+ end
+ def open(state)
+ state.endline()
+ state.needs_semi = false
+ state.print("namespace #{@name} {\n")
+ end
+ def adjust_from(state,old_group)
+ close_grps = []
+ grp = old_group
+ while(grp)
+ close_grps << grp
+ grp = grp.parent
+ end
+ open_grps = []
+ grp = self
+ while(grp)
+ open_grps << grp
+ grp = grp.parent
+ end
+ while(open_grps[-1] == close_grps[-1] && close_grps[-1])
+ close_grps.pop()
+ open_grps.pop()
+ end
+ close_grps.each do |grp|
+ grp.close(state)
+ end
+ open_grps.reverse.each do |grp|
+ grp.open(state)
+ end
+ end
+ def adjust_to(state,new_group)
+ grp = self
+ while(grp)
+ grp.close(state)
+ grp = grp.parent
+ end
+ end
+end
+class GroupPlan < GroupElement
+ attr_accessor :implicit
+ def initialize(group_elem,members = [])
+ @group_elem = group_elem
+ @members = CPP::Suite.new(members)
+ end
+ def push(mem)
+ mem.add_group_dep(@implicit) if(@implicit)
+ @members << mem
+ end
+ def pp(state)
+ if(@group_elem)
+ @group_elem.open(state)
+ end
+ group = nil
+ @members.each do |member|
+ group = member.adjust_group(state,group)
+ #puts "at:#{group.name}" if(group.respond_to?(:name))
+ state.endline()
+ state.needs_semi = true
+ state.pp(member)
+ state.endline()
+ end
+ group.adjust_to(state,nil) if(group)
+ if(@group_elem)
+ @group_elem.close(state)
+ end
+ end
+end
+class SWIGPre_Mask
+ def initialize(elem)
+ @elem = elem
+ end
+ def plan_cc(plan)
+ end
+ def plan_pre_swig(plan)
+ elem = MemberElementPreSWIG.new(@elem)
+ plan.push(elem)
+ end
+ def plan_post_swig(plan)
+ end
+ def plan_header(plan);
+ end
+end
+class SWIGPost_Mask
+ def initialize(elem)
+ @elem = elem
+ end
+ def plan_cc(plan)
+ end
+ def plan_pre_swig(plan)
+ end
+ def plan_post_swig(plan)
+ elem = MemberElementPostSWIG.new(@elem)
+ plan.push(elem)
+ end
+ def plan_header(plan);
+ end
+end
+class CC_Mask
+ def initialize(elem)
+ @elem = elem
+ end
+ def plan_cc(plan)
+ elem = MemberElementCC.new(@elem)
+ elem.pp_override = true
+ plan.push(elem)
+ end
+ def plan_header(plan);
+ end
+ def plan_pre_swig(plan);
+ end
+ def plan_post_swig(plan);
+ end
+end
+module Types
+ class TypeDef
+ def initialize(type,name)
+ @type = type
+ @name = name
+ end
+ def pp(state)
+ state.pp("typedef #{@type.name} #{@name}")
+ end
+ end
+ class Type
+ attr_accessor :name,:static,:dec,:space
+ def initialize(namespace,name)
+ @space = namespace
+ @name = name
+ @members = []
+ @protections = {}
+ @deps = []
+ end
+ class ProtectionGroup
+ def initialize(name)
+ @name = name
+ end
+ def adjust_from(state,other)
+ state.indent -= 1
+ state.pp("#@name:")
+ state.endline
+ state.indent += 1
+ end
+ def adjust_to(state,other)
+ other.adjust_from(state,self) if other
+ end
+ end
+ ProtectionGroups = { :public => ProtectionGroup.new(:public),
+ :protected => ProtectionGroup.new(:protected),
+ :private => ProtectionGroup.new(:private)}
+ def set_parent(parent)
+ @parent = parent
+ end
+ def chop_method_prefix()
+ @space.chop_method_prefix + "#@name::"
+ end
+ def def_func(*args)
+ func = CPP::MemberFunc.new(self,*args)
+ @protections[func] = @protection
+ @members << func
+ return func
+ end
+ def add_cc_comment(*args)
+ args.each do |arg|
+ @members.push(CC_Mask.new(CPP::Comment.new(arg)))
+ end
+ end
+ def add_pre_swig(arg)
+ @members.push(SWIGPre_Mask.new(arg))
+ end
+ def add_post_swig(arg)
+ @members.push(SWIGPost_Mask.new(arg))
+ end
+ def plan_pre_swig(plan)
+ @members.each do |member|
+ if(member.respond_to?(:plan_pre_swig))
+ member.plan_pre_swig(plan)
+ elsif(member.respond_to?(:pp_pre_swig_file))
+ plan.push(MemberElementPreSWIG.new(member))
+ end
+ end
+ end
+ def plan_post_swig(plan)
+ @members.each do |member|
+ if(member.respond_to?(:plan_post_swig))
+ member.plan_post_swig(plan)
+ elsif(member.respond_to?(:pp_post_swig_file))
+ plan.push(MemberElementPostSWIG.new(member))
+ end
+ end
+ end
+ def plan_cc(plan)
+ @members.each do |member|
+ if(member.respond_to?(:plan_cc))
+ member.plan_cc(plan)
+ elsif(member.respond_to?(:pp_cc_file))
+ plan.push(MemberElementCC.new(member))
+ end
+ end
+ end
+ def plan_header(plan)
+ group_plan = GroupPlan.new(self)
+ plan.push(group_plan)
+ @members.each do |member|
+ group_plan.implicit = ProtectionGroups[@protections[member]]
+ if(member.respond_to?(:plan_header))
+ member.plan_header(group_plan)
+ else
+ group_plan.push(MemberElementHeader.new(member))
+ end
+ #member.plan_cc(plan)
+ end
+ end
+ def open(state)
+ state.needs_semi = false
+ state.v_pad(2)
+ if(@static)
+ state.print("static ")
+ end
+ self.template_header(state) if(self.respond_to?(:template_header))
+ state.print("#{self.class.type_name} #{@name}")
+ self.template_spec_args(state) if(self.respond_to?(:template_spec_args))
+ if(@parent)
+ state.print(" : #{@parent} {\n")
+ else
+ state.pp(" {\n")
+ end
+ state.indent += 2
+ end
+ def close(state)
+ state.indent -= 2
+ state.needs_semi = true
+ if(@dec)
+ state.print("\n} #{@dec}")
+ else
+ state.print("\n}")
+ end
+ state.v_pad(2)
+ end
+ def add_dep(other)
+ @deps << other
+ self
+ end
+ end
+ class Class < Type
+ def add_member(protection,member)
+ @protection = protection
+ @members.push(member)
+ @protections[member] = protection
+ return member
+ end
+ def add_struct(*args)
+ add_member(:public, Types::Struct.new(self,*args))
+ end
+ def public() ; @protection = :public ; end
+ def protected() ; @protection = :protected ; end
+ def private() ; @protection = :private ; end
+ def self.type_name() ; "class" ; end
+ end
+ class PreprocessorIf < Type
+ def initialize(*args)
+ super(*args)
+ end
+ def add_member(member)
+ @members.push(member)
+ return member
+ end
+ def self.type_name() ; "#if" ; end
+ def open(state)
+ state.needs_semi = false
+ state.print("\n#if #{@name}")
+ end
+ def close(state)
+ state.needs_semi = false
+ state.print("\n#endif // #{@name}")
+ end
+ end
+ class Struct < Type
+ def add_member(member)
+ @members.push(member)
+ return member
+ end
+ def self.type_name() ; "struct" ; end
+ end
+ class TemplateClass < Class
+ def initialize(*args)
+ super(*args)
+ @t_args = CPP::Args.new()
+ end
+ def spec_args()
+ return @spec_args ||= CPP::Args.new()
+ end
+ def template_header(state)
+ if(@t_args.length > 0)
+ state.pp("template < ")
+ state.pp(@t_args)
+ else
+ state.pp("template <")
+ end
+ state.pp(">\n")
+ end
+ def plan_cc(plan)
+
+ end
+ def plan_header(plan)
+ group_plan = GroupPlan.new(self)
+ plan.push(group_plan)
+ @members.each do |member|
+ group_plan.implicit = ProtectionGroups[@protections[member]]
+ if(member.respond_to?(:plan_header))
+ member.plan_header(group_plan)
+ else
+ group_plan.push(MemberElementInline.new(member))
+ end
+ end
+ end
+ def template_spec_args(state)
+ if(@spec_args)
+ state.pp("< ")
+ state.pp(@spec_args)
+ state.pp(">")
+ end
+ end
+ end
+end
+class DepFilePair
+ class NameSpace
+ def initialize(name,parent)
+ @name,@parent = name,parent
+ @members = []
+ end
+ def add_struct(*args)
+ add Types::Struct.new(self,*args)
+ end
+ def add_template(*args)
+ add Types::TemplateClass.new(self,*args)
+ end
+ def add_class(*args)
+ add Types::Class.new(self,*args)
+ end
+ def add_cc(arg)
+ @members.push(CC_Mask.new(arg))
+ end
+ def add_pre_swig(arg)
+ @members.push(SWIGPre_Mask.new(arg))
+ end
+ def add_post_swig(arg)
+ @members.push(SWIGPost_Mask.new(arg))
+ end
+ def chop_method_prefix()
+ ""
+ end
+ def class_comment(*args)
+ add CPP::Comment.new(*args)
+ end
+ def var_dec_comment(*args)
+ add CPP::Comment.new(*args)
+ end
+ def add_var_dec(arg)
+ add DepMask.new(arg)
+ end
+ def plan_pre_swig(plan)
+ plan.implicit = ImplicitName.new(@name,plan.implicit)
+ @members.each do |member|
+ if(member.respond_to?(:plan_pre_swig))
+ member.plan_pre_swig(plan)
+ else
+ MemberElementPreSWIG.check(plan,member)
+ end
+ end
+ end
+ def plan_post_swig(plan)
+ @members.each do |member|
+ if(member.respond_to?(:plan_post_swig))
+ member.plan_post_swig(plan)
+ else
+ MemberElementPostSWIG.check(plan,member)
+ end
+ end
+ end
+ def plan_cc(plan)
+ plan.implicit = ImplicitName.new(@name,plan.implicit)
+ @members.each do |member|
+ if(member.respond_to?(:plan_cc))
+ member.plan_cc(plan)
+ else
+ MemberElementCC.check(plan,member)
+ end
+ end
+ plan.implicit = plan.implicit.parent
+ end
+ def plan_header(plan)
+ plan.implicit = ImplicitName.new(@name,plan.implicit)
+ @members.each do |member|
+ if(member.respond_to?(:plan_header))
+ member.plan_header(plan)
+ else
+ MemberElementHeader.check(plan,member)
+ end
+ end
+ plan.implicit = plan.implicit.parent
+ end
+ def add val
+ @members << val
+ val
+ end
+ end
+ def initialize(rel_path)
+ @rel_path = rel_path
+ @cc_includes = []
+ @swig_includes_h = []
+ @swig_includes_swig = []
+ @header_includes = []
+ @spaces = []
+ @cc_usings = []
+ @cache = {}
+ end
+ def add_swig_body_include(inc_path)
+ @swig_includes_swig << CPP::SwigInclude.new(inc_path)
+ end
+ def add_swig_header_include(inc_path)
+ @swig_includes_h << CPP::Include.new(inc_path)
+ end
+ def add_swig_include(inc_path)
+ @swig_includes_h << CPP::Include.new(inc_path)
+ @swig_includes_swig << CPP::SwigInclude.new(inc_path)
+ end
+ def add_cc_include(inc_path)
+ @cc_includes << CPP::Include.new(inc_path)
+ end
+ def add_cc_using(using)
+ @cc_usings << CPP::Using.new(using)
+ end
+ def add_header_include(inc_path)
+ @header_includes << CPP::Include.new(inc_path)
+ end
+ def add_namespace(name,parent)
+ space = NameSpace.new(name,parent)
+ if(parent != self)
+ parent.add(space)
+ else
+ @spaces.push(space)
+ end
+ return space
+ end
+ def set(type,cached)
+ @cache[type] = cached
+ end
+ def get(type)
+ cached = @cache[type]
+ return cached if cached
+ cached = type.create(self)
+ cached_check = @cache[type]
+ return cached_check if cached_check
+ set(type,cached)
+ return cached
+ end
+ def write_cc_file(cpp_base,cc_file)
+ plan_cc = GroupPlan.new(nil,elems_cc = [])
+ @spaces.each do |space|
+ space.plan_cc(plan_cc)
+ end
+ suite = CPP::Suite.new(@cc_includes + @cc_usings + [plan_cc])
+ CPP.pretty_print(suite,cc_file)
+ end
+ def write_header_file(cpp_base,header_file)
+ plan_header = GroupPlan.new(nil,elems_cc = [])
+ @spaces.each do |space|
+ space.plan_header(plan_header)
+ end
+ suite = CPP::Suite.new(@header_includes + [plan_header])
+ include_guard = CPP::IncludeGuard.new(suite)
+ include_guard.name = @rel_path.upcase.gsub(/[\.\/\\]/,"_") + "_H_"
+ CPP.pretty_print(include_guard,header_file)
+ end
+ def write_swig_file(cpp_base,swig_file,q_filename)
+ plan_pre_swig = GroupPlan.new(nil, elems_cc = [])
+ plan_post_swig = GroupPlan.new(nil, elems_cc = [])
+ q_filename_underscore = q_filename.gsub(".","_")
+ @spaces.each do |space|
+ space.plan_pre_swig(plan_pre_swig)
+ space.plan_post_swig(plan_post_swig)
+ end
+ header_includes = CPP::SWIGBraces.new(CPP::Suite.new(@swig_includes_h))
+ # TODO(aschuh): I should probably %import any other headers from this queue's dependencies.
+ suite = CPP::Suite.new(["%module \"#{q_filename_underscore}\"",
+ "%typemap(javaimports) SWIGTYPE, SWIGTYPE * \"import aos.QueueGroup; import aos.Message; import aos.Time;\"",
+ "%pragma(java) jniclassimports=\"import aos.QueueGroup; import aos.Message; import aos.Time;\"",
+ "%pragma(java) moduleimports=\"import aos.QueueGroup; import aos.Message; import aos.Time;\"",
+ "%include \"std_string.i\"",
+ "%include \"stdint.i\""] +
+ [header_includes] +
+ #["%import \"aos/common/time.h\"",
+ #"%import \"aos/common/queue.h\""] +
+ ["%import \"aos/aos.swig\""] +
+ [plan_pre_swig] +
+ @swig_includes_swig +
+ [plan_post_swig]
+ )
+ CPP.pretty_print(suite, swig_file)
+ end
+end
diff --git a/aos/build/queues/cpp_pretty_print/file_pair_types.rb b/aos/build/queues/cpp_pretty_print/file_pair_types.rb
new file mode 100644
index 0000000..8f60b77
--- /dev/null
+++ b/aos/build/queues/cpp_pretty_print/file_pair_types.rb
@@ -0,0 +1,204 @@
+module CPP
+end
+class CPP::TypePair
+ attr_accessor :name,:static,:dec
+ def initialize(namespace,name)
+ @space,@name = namespace,name
+ @members = []
+ @protections = {}
+ @dont_sort = {}
+ end
+ ProtectionTable = { :public => 0,:protected => 1,:private => 2 }
+ def comp(m1,m2)
+ if(!(@dont_sort[m1] || @dont_sort[m2]))
+ if(@protections[m1] && @protections[m2])
+ comp = ProtectionTable[@protections[m1]] <=> ProtectionTable[@protections[m2]]
+ return comp if(comp != 0)
+ end
+ comp = TypeTable[m1.class] <=> TypeTable[m2.class]
+ return comp if(comp != 0)
+ end
+ return @stable[m1] <=> @stable[m2]
+ end
+ def set_parent(parent)
+ @parent = parent
+ end
+ def add_class(name)
+ return add_member(:public,CPP::ClassPair.new(self,name))
+ end
+ def add_struct(name)
+ return add_member(:public,CPP::StructPair.new(self,name))
+ end
+ def add_cc_comment(*strs)
+ strs.each do |str|
+ @members << comment = CPP::CCMemberWrapper.new(CPP::Comment.new(str))
+ @protections[comment] = @protection
+ end
+ #@dont_sort[comment] = true
+ end
+ def method_prefix()
+ @space.method_prefix + "#@name::"
+ end
+ def chop_method_prefix()
+ @space.chop_method_prefix + "#@name::"
+ end
+ def pp(state)
+ @stable = {}
+ @members.each_with_index { |mem,i| @stable[mem] = i }
+ members = @members.sort { |m1,m2| comp(m1,m2) }
+
+ state.needs_semi = false
+ state.v_pad(2)
+ if(@static)
+ state.print("static ")
+ end
+ if(@parent)
+ state.print("#{self.class.type_name} #{@name} : #{@parent} {\n")
+ else
+ state.print("#{self.class.type_name} #{@name} {\n")
+ end
+ state.indent += 2
+ protection = nil
+ members.each do |member|
+ if(protection != @protections[member])
+ state.indent -= 1
+ state.needs_semi = false
+ state.v_pad(2) if(protection)
+ protection = @protections[member]
+ state.print("#{protection}:\n")
+ state.indent += 1
+ state.endline()
+ end
+ state.endline()
+ state.needs_semi = true
+ if(member.respond_to?(:pp_header_file))
+ member.pp_header_file(state)
+ else
+ state.pp(member)
+ end
+ state.endline()
+ end
+ state.indent -= 2
+ state.needs_semi = true
+ if(@dec)
+ state.print("\n} #{@dec}")
+ else
+ state.print("\n}")
+ end
+ state.v_pad(2)
+ end
+ def pp_header_file(state)
+ pp(state)
+ end
+ def pp_cc_file(state)
+ @members.each do |member|
+ state.needs_semi = true
+ member.pp_cc_file(state) if(member.respond_to?(:pp_cc_file))
+ state.endline()
+ end
+ end
+ def def_func(*args)
+ func = CPP::MemberFunc.new(self,*args)
+ @protections[func] = @protection
+ @members << func
+ return func
+ end
+end
+class CPP::CCMemberWrapper
+ def initialize(member)
+ @member = member
+ end
+ def pp_header_file(state) ; end
+ def pp_cc_file(state)
+ state.pp(@member)
+ end
+end
+class CPP::ClassPair < CPP::TypePair
+ attr_accessor :name
+ def initialize(namespace,name)
+ super(namespace,name)
+ @protection = :public #default to public
+ end
+ def add_member(protection,member)
+ @protection = protection
+ @members << member
+ @protections[member] = protection
+ return member
+ end
+ def public() ; @protection = :public ; end
+ def protected() ; @protection = :protected ; end
+ def private() ; @protection = :private ; end
+ def self.type_name() ; "class" ; end
+end
+class CPP::StructPair < CPP::TypePair
+ def self.type_name() ; "struct" ; end
+ def add_member(member)
+ @members << member
+ return member
+ end
+end
+CPP::TypePair::TypeTable = { CPP::StructPair => 0, CPP::ClassPair => 1,CPP::Constructor => 2 }
+CPP::TypePair::TypeTable.default = 3
+class CPP::TemplateClass < CPP::ClassPair
+ def initialize(namespace,name)
+ super(namespace,name)
+ @t_args = CPP::Args.new()
+ end
+ def spec_args()
+ return @spec_args ||= CPP::Args.new()
+ end
+ def pp(state)
+ @stable = {}
+ @members.each_with_index { |mem,i| @stable[mem] = i }
+ members = @members.sort { |m1,m2| comp(m1,m2) }
+ state.needs_semi = false
+ state.v_pad(2)
+ if(@t_args.length > 0)
+ state.pp("template < ")
+ state.pp(@t_args)
+ else
+ state.pp("template <")
+ end
+ state.pp(">\n")
+ state.pp("class #@name")
+ if(@spec_args)
+ state.pp("< ")
+ state.pp(@spec_args)
+ state.pp("> {")
+ else
+ state.pp(" {")
+ end
+ state.endline()
+ state.indent += 2
+ protection = nil
+ members.each do |member|
+ if(protection != @protections[member])
+ state.indent -= 1
+ state.needs_semi = false
+ state.v_pad(2) if(protection)
+ protection = @protections[member]
+ state.print("#{protection}:\n")
+ state.indent += 1
+ state.endline()
+ end
+ state.endline()
+ state.needs_semi = true
+ if(member.respond_to?(:pp_inline))
+ member.pp_inline(state)
+ else
+ state.pp(member)
+ end
+ state.endline()
+ end
+ state.indent -= 2
+ state.needs_semi = true
+ if(@dec)
+ state.print("\n} #{@dec}")
+ else
+ state.print("\n}")
+ end
+ state.v_pad(2)
+ end
+ def pp_cc_file(state); end
+end
+
diff --git a/aos/build/queues/cpp_pretty_print/standard_types.rb b/aos/build/queues/cpp_pretty_print/standard_types.rb
new file mode 100644
index 0000000..566f542
--- /dev/null
+++ b/aos/build/queues/cpp_pretty_print/standard_types.rb
@@ -0,0 +1,363 @@
+module CPP
+ class Class
+
+ end
+ class Funct
+ attr_accessor :retval,:name,:args,:suite
+ def initialize(retval = nil,name = nil,args = Args.new(),suite = Suite.new())
+ @retval,@name,@args,@suite = retval,name,args,suite
+ end
+ def pp(state)
+ state.pp(@retval)
+ state.print(" ")
+ state.pp(@name)
+ state.print("(")
+ state.pp(@args)
+ state.print(")")
+ state.pp(@suite)
+ end
+ end
+ class If
+ attr_accessor :cond,:suite,:else_suite
+ def initialize(cond = nil,suite = Suite.new(),else_suite = nil)
+ @cond,@suite,@else_suite = cond,suite,else_suite
+ end
+ def pp(state)
+ state.print("if (")
+ state.pp(@cond)
+ state.print(") ")
+ state.needs_semi = false
+ state.pp(@suite)
+ if(@else_suite)
+ state.print(" else ")
+ state.pp(@else_suite)
+ end
+ end
+ def else_suite()
+ return(@else_suite ||= Suite.new())
+ end
+ end
+ class For
+ attr_accessor :init,:cond,:update,:suite
+ def initialize(init = nil,cond = nil,update = nil,suite = Suite.new())
+ @init,@cond,@update,@suite = init,cond,update,suite
+ end
+ def pp(state)
+ state.print("for (")
+ Args.new([@init,@cond,@update]).pp(state,";")
+ state.print(") ")
+ state.needs_semi = false
+ state.pp(@suite)
+ end
+ end
+ class Args < Array
+ attr_accessor :dont_wrap
+ def pp(state,sep = ",")
+ pos = start = state.col
+ self.each_with_index do |arg,i|
+ #puts "#{state.col - start} , #{start}"
+ state.print(sep) if(i != 0)
+ if(pos > 80)
+ state.wrap(state.indent + 4)
+ pos = start = state.col
+ elsif(state.col * 2 - pos > 80 && !@dont_wrap)
+ state.wrap(start)
+ start = pos
+ else
+ state.print(" ") if(i != 0)
+ pos = state.col
+ end
+ state.pp(arg)
+ end
+ end
+ end
+ class Suite < Array
+ def pp(state)
+ state.print("{")
+ state.>>
+ state.needs_semi = false
+ self.pp_no_braces(state)
+ state.<<
+ state.print("}")
+ end
+ def pp_no_braces(state)
+ self.each do |arg,i|
+ state.endline()
+ state.needs_semi = true
+ state.pp(arg)
+ state.endline()
+ end
+ end
+ def pp_one_line(state)
+ if(self.length == 1)
+ state.needs_semi = true
+ state.print("{ ")
+ state.pp(self[0])
+ state.print(";") if(state.needs_semi)
+ state.needs_semi = false
+ state.print(" }")
+ else
+ self.pp(state)
+ end
+ end
+ end
+ class FuncCall
+ attr_accessor :name,:args
+ def initialize(name = nil,args = Args.new())
+ @name,@args = name,args
+ end
+ def self.build(name,*args)
+ self.new(name,Args.new(args))
+ end
+ def pp(state)
+ state.pp(@name)
+ state.print("(")
+ state.pp(@args)
+ state.print(")")
+ end
+ end
+ class BIT_OR
+ attr_accessor :val1,:val2
+ def initialize(val1,val2)
+ @val1,@val2 = val1,val2
+ end
+ def pp(state)
+ state.pp(@val1)
+ state.print(" | ")
+ state.pp(@val2)
+ end
+ end
+ class LT
+ attr_accessor :val1,:val2
+ def initialize(val1,val2)
+ @val1,@val2 = val1,val2
+ end
+ def pp(state)
+ state.pp(@val1)
+ state.print(" < ")
+ state.pp(@val2)
+ end
+ end
+ class Div
+ attr_accessor :val1,:val2
+ def initialize(val1,val2)
+ @val1,@val2 = val1,val2
+ end
+ def pp(state)
+ state.pp(@val1)
+ state.print(" / ")
+ state.pp(@val2)
+ end
+ end
+ class Add
+ attr_accessor :val1,:val2
+ def initialize(val1,val2)
+ @val1,@val2 = val1,val2
+ end
+ def pp(state)
+ state.pp(@val1)
+ state.print(" + ")
+ state.pp(@val2)
+ end
+ end
+ class Member
+ attr_accessor :obj,:name
+ def initialize(obj,name)
+ @obj,@name = obj,name
+ end
+ def pp(state)
+ state.pp(@obj)
+ state.print(".")
+ state.pp(@name)
+ end
+ end
+ class PointerMember
+ attr_accessor :obj,:name
+ def initialize(obj,name)
+ @obj,@name = obj,name
+ end
+ def pp(state)
+ state.pp(@obj)
+ state.print("->")
+ state.pp(@name)
+ end
+ end
+ class Minus
+ attr_accessor :val
+ def initialize(val)
+ @val = val
+ end
+ def pp(state)
+ state.print("-")
+ state.pp(@val)
+ end
+ end
+ class Not
+ attr_accessor :val
+ def initialize(val)
+ @val = val
+ end
+ def pp(state)
+ state.print("!")
+ state.pp(@val)
+ end
+ end
+ class Address
+ attr_accessor :val
+ def initialize(val)
+ @val = val
+ end
+ def pp(state)
+ state.print("&")
+ state.pp(@val)
+ end
+ end
+ class Paran
+ attr_accessor :val
+ def initialize(val)
+ @val = val
+ end
+ def pp(state)
+ state.print("(")
+ state.pp(@val)
+ state.print(")")
+ end
+ end
+ class Assign
+ attr_accessor :lval,:rval
+ def initialize(lval = nil,rval = Args.new())
+ @lval,@rval = lval,rval
+ end
+ def pp(state)
+ state.pp(@lval)
+ state.print(" = ")
+ state.pp(@rval)
+ end
+ end
+ class PointerDeref
+ attr_accessor :val
+ def initialize(val)
+ @val = val
+ end
+ def pp(state)
+ state.print("*")
+ state.pp(@val)
+ end
+ end
+ class Cast
+ attr_accessor :to,:val
+ def initialize(to,val)
+ @to,@val = to,val
+ end
+ def pp(state)
+ state.print("(")
+ state.pp(@to)
+ state.print(")")
+ state.pp(@val)
+ end
+ end
+ class VarDec
+ attr_accessor :type,:name
+ def initialize(type = nil,name = nil)
+ @type,@name = type,name
+ end
+ def pp(state)
+ state.pp(@type)
+ state.print(" ")
+ state.pp(@name)
+ end
+ end
+ class Return
+ attr_accessor :val
+ def initialize(val = nil)
+ @val = val
+ end
+ def pp(state)
+ state.print("return ")
+ state.pp(@val)
+ end
+ end
+ class TraversalState
+ attr_accessor :needs_semi,:indent,:col
+ def initialize(file)
+ @file = file
+ @indent = 0
+ @not_indented = true
+ @just_endlined = true
+ @hold_points = []
+ @col = 0
+ end
+ def set_hold_point()
+ @hold_points.push(@col)
+ end
+ def wrap(col)
+ @file.print("\n")
+ @file.print(" " * col)
+ @col = col
+ end
+ def suppress_indent()
+ @not_indented = false
+ end
+ def <<()
+ @indent -= 2
+ end
+ def >>()
+ @indent += 2
+ end
+ def pp(ast)
+ return ast.pp(self) if(ast.respond_to?(:pp))
+ self.print(ast)
+ end
+ def print(chars)
+ return print_no_split(chars) if(!chars.respond_to?(:split))
+ chars.split(/\n/,-1).each_with_index do |line,i|
+ endline() if(i != 0)
+ print_no_split(line) if(line && line.length > 0)
+ end
+ end
+ def print_no_split(chars)
+ if(@not_indented)
+ @file.print(" "*@indent)
+ @col += @indent
+ @not_indented = false
+ end
+ if(chars)
+ chars = chars.to_s
+ if(chars.length > 0)
+ @col += chars.length
+ @file.print(chars)
+ @just_endlined = false
+ @v_pad = 0
+ end
+ end
+ end
+ def endline()
+ return if(@just_endlined)
+ @file.print(";") if(@needs_semi)
+ @needs_semi = false
+ @file.print("\n")
+ @not_indented = true
+ @just_endlined = true
+ @hold_points.clear()
+ @v_pad += 1
+ @col = 0
+ end
+ def v_pad(n)
+ while(@v_pad < n)
+ force_endline()
+ end
+ end
+ def force_endline()
+ @just_endlined = false
+ endline()
+ end
+ end
+ def self.pretty_print(ast,file)
+ state = TraversalState.new(file)
+ if(ast.respond_to?(:pp_no_braces))
+ ast.pp_no_braces(state)
+ else
+ state.pp(ast)
+ end
+ end
+end
diff --git a/aos/build/queues/cpp_pretty_print/swig.rb b/aos/build/queues/cpp_pretty_print/swig.rb
new file mode 100644
index 0000000..ac6d062
--- /dev/null
+++ b/aos/build/queues/cpp_pretty_print/swig.rb
@@ -0,0 +1,60 @@
+class CPP::SwigPragma
+ attr_accessor :suite
+ def initialize(language, pragmatype, suite = CPP::Suite.new())
+ @suite = suite
+ @language = language
+ @pragmatype = pragmatype
+ end
+ def pp(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("%pragma(#{@language}) #{@pragmatype}=%{")
+ state.endline()
+ if(@suite.respond_to?(:pp_no_braces))
+ @suite.pp_no_braces(state)
+ else
+ state.pp(@suite)
+ end
+ state.endline()
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("%}")
+ state.endline()
+ state.endline()
+ end
+end
+class CPP::SWIGBraces
+ attr_accessor :suite
+ def initialize(suite = CPP::Suite.new())
+ @suite = suite
+ end
+ def pp(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("%{")
+ state.endline()
+ if(@suite.respond_to?(:pp_no_braces))
+ @suite.pp_no_braces(state)
+ else
+ state.pp(@suite)
+ end
+ state.endline()
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("%}")
+ state.endline()
+ state.endline()
+ end
+end
+class CPP::SwigInclude
+ attr_accessor :filename
+ def initialize(filename)
+ @filename = filename
+ end
+ def pp(state)
+ state.needs_semi = false
+ state.suppress_indent()
+ state.print("%include #{@filename}")
+ state.endline()
+ end
+end
diff --git a/aos/build/queues/objects/errors.rb b/aos/build/queues/objects/errors.rb
new file mode 100644
index 0000000..d776a22
--- /dev/null
+++ b/aos/build/queues/objects/errors.rb
@@ -0,0 +1,43 @@
+class QError < Exception
+ def initialize(msg)
+ super()
+ @msg = msg
+ @qstacktrace = []
+ end
+ def self.set_name(name)
+ @pretty_name = name
+ end
+ def self.pretty_name()
+ @pretty_name
+ end
+ def to_s
+ msg = "Error:(#{self.class.pretty_name})\n\t"
+ msg += @msg
+ msg += "\n" if(msg[-1] != "\n")
+ @qstacktrace.each do |part|
+ part = part.q_stack_name if(part.respond_to?(:q_stack_name))
+ msg += "\tfrom: #{part}\n"
+ end
+ return msg
+ end
+ set_name("Base Level Exception.")
+ attr_accessor :qstacktrace
+end
+class QSyntaxError < QError
+ def initialize(msg)
+ super(msg)
+ end
+ set_name("Syntax Error")
+end
+class QNamespaceCollision < QError
+ def initialize(msg)
+ super(msg)
+ end
+ set_name("Namespace Collision")
+end
+class QImportNotFoundError < QError
+ def initialize(msg)
+ super(msg)
+ end
+ set_name("Couldn't Find Target of Import Statement")
+end
diff --git a/aos/build/queues/objects/interface.rb b/aos/build/queues/objects/interface.rb
new file mode 100644
index 0000000..52332b6
--- /dev/null
+++ b/aos/build/queues/objects/interface.rb
@@ -0,0 +1,69 @@
+class MessageElementReq
+ def initialize(type,name)
+ @type = type
+ @name = name
+ end
+ def self.parse(tokens)
+ type = tokens.expect(:tWord).data
+ name = tokens.expect(:tWord).data
+ tokens.expect(:tSemi)
+ return self.new(type,name)
+ end
+end
+class QueueReq
+ def initialize(name,type = nil)
+ @name = name
+ @type = type
+ end
+ def self.parse(tokens)
+ type_or_name = tokens.expect(:tWord).data
+ if(tokens.peak == :tSemi)
+ tokens.expect(:tSemi)
+ return self.new(type_or_name)
+ else
+ name = tokens.expect(:tWord).data
+ tokens.expect(:tSemi)
+ return self.new(name,type_or_name)
+ end
+ end
+end
+class InterfaceStmt < QStmt
+ def initialize(name,elements)
+ @name = name
+ @elements = elements
+ end
+ def q_eval(locals)
+
+ end
+ def self.check_type(tokens,new_type,old_type)
+ return new_type if(old_type == nil)
+ if(new_type != old_type)
+ tokens.qError(<<ERROR_MSG)
+error: intermixing queue definitions (a queue_group feature)
+ and type definitions (a message_group feature)
+ this results in an undefined type value.
+ Wot. Wot.
+ERROR_MSG
+ end
+ return old_type
+ end
+ def self.parse(tokens)
+ name = tokens.expect(:tWord).data
+ values = []
+ type = nil
+ tokens.expect(:tOpenB)
+ while(tokens.peak != :tCloseB)
+ if(tokens.peak.data == "queue")
+ tokens.expect(:tWord)
+ values << QueueReq.parse(tokens)
+ type = check_type(tokens,:queue_group,type)
+ else
+ values << MessageElementReq.parse(tokens)
+ type = check_type(tokens,:message_group,type)
+ end
+ end
+ tokens.expect(:tCloseB)
+ tokens.expect(:tSemi)
+ self.new(name,values)
+ end
+end
diff --git a/aos/build/queues/objects/namespaces.rb b/aos/build/queues/objects/namespaces.rb
new file mode 100644
index 0000000..b799d36
--- /dev/null
+++ b/aos/build/queues/objects/namespaces.rb
@@ -0,0 +1,210 @@
+class LocalSituation
+ attr_accessor :globals,:local
+ def initialize(globals)
+ @globals = globals
+ @local = nil
+ end
+ def package=(qualified)
+ if(@local)
+ raise QSyntaxError.new(<<ERROR_MSG)
+You are redefining the package path.
+ Stuff might break if you do that.
+ Other options include: using another header file, and just using the same namespace.
+ If you are confident that you need this you can remove this check at
+ #{__FILE__}:#{__LINE__}.
+ Or file a feature request.
+ But that would be weird...
+ Wot. Wot.
+ERROR_MSG
+ end
+ @local = @globals.space
+ qualified.names.each do |name|
+ @local = @local.get_make(name)
+ end
+ end
+ def register(value)
+ if(!@local)
+ raise QError.new(<<ERROR_MSG)
+There is no package path defined, This is a big problem because
+ we are kindof expecting you to have a package path...
+ use a :
+ package my_super.cool.project;
+ statement to remedy this situation. (or file a feature request)
+ Wot. Wot.
+ERROR_MSG
+ end
+ @local[value.name] = value
+ value.parent = @local if(value.respond_to?(:parent=))
+ value.loc = @local
+ end
+ def bind(bind_to)
+ return BoundSituation.new(self,bind_to)
+ end
+end
+class BoundSituation < LocalSituation
+ def initialize(locals,bind_to)
+ @globals = globals
+ @local = bind_to
+ end
+end
+class NameSpace
+ attr_accessor :parent,:name
+ def initialize(name = nil,parent = nil)
+ @name = name
+ @parent = parent
+ @spaces = {}
+ end
+ def []=(key,val)
+ if(old_val = @spaces[key])
+ old_val = old_val.created_by if(old_val.respond_to?(:created_by) && old_val.created_by)
+ if(old_val.respond_to?(:q_stack_name))
+ old_val = old_val.q_stack_name
+ else
+ old_val = "eh, it is a #{old_val.class} thats all I know..."
+ end
+ raise QNamespaceCollision.new(<<ERROR_MSG)
+Woah! The name #{queue_name(key).inspect} is already taken by some chap at #{old_val}.
+\tFind somewhere else to peddle your wares.
+\tWot. Wot.
+ERROR_MSG
+ end
+ @spaces[key] = val
+ end
+ def to_cpp_id(name)
+ txt = @name + "::" + name
+ return @parent.to_cpp_id(txt) if(@parent && parent.name)
+ return "::" + txt
+ end
+ def queue_name(queue)
+ get_name() + "." + queue
+ end
+ def [](key)
+ #puts "getting #{get_name}.#{key}"
+ @spaces[key]
+ end
+ def get_make(name)
+ @spaces[name] ||= self.class.new(name,self)
+ end
+ def get_name()
+ if(@parent)
+ return "#{@parent.get_name}.#{@name}"
+ else
+ return "#{@name}"
+ end
+ end
+ def create(cpp_tree)
+ if(@parent && @parent.name)
+ parent = cpp_tree.get(@parent)
+ else
+ parent = cpp_tree
+ end
+ return cpp_tree.add_namespace(@name,parent)
+ end
+ def to_s()
+ "<NameSpace: #{get_name()}>"
+ end
+ def inspect()
+ "<NameSpace: #{get_name()}>"
+ end
+ def root()
+ return self if(@parent == nil)
+ return @parent.root
+ end
+end
+class Globals
+ attr_accessor :space
+ def initialize()
+ @space = NameSpace.new()
+ @space.get_make("aos")
+ @include_paths = []
+ end
+ def paths()
+ @include_paths
+ end
+ def add_path(path)
+ @include_paths << path
+ end
+ def find_file(filename)
+ @include_paths.each do |path_name|
+ new_path = File.expand_path(path_name) + "/" + filename
+ if(File.exists?(new_path))
+ return new_path
+ end
+ end
+ raise QImportNotFoundError.new(<<ERROR_MSG)
+Problem Loading:#{filename.inspect} I looked in:
+\t#{(@include_paths.collect {|name| name.inspect}).join("\n\t")}
+\tbut alas, it was nowhere to be found.
+\tIt is popular to include the top of the repository as the include path start,
+\tand then reference off of that.
+\tI would suggest doing that and then trying to build again.
+\tWot. Wot.
+ERROR_MSG
+ end
+end
+class QualifiedName
+ attr_accessor :names,:off_root
+ def initialize(names,off_root = false)
+ @names = names
+ @off_root = off_root
+ end
+ def test_lookup(namespace)
+ @names.each do |name|
+ namespace = namespace[name]
+ return nil if(!namespace)
+ end
+ return namespace
+ end
+ def is_simple?()
+ return !@off_root && @names.length == 1
+ end
+ def to_simple()
+ return @names[-1]
+ end
+ def to_s()
+ if(@off_root)
+ return ".#{@names.join(".")}"
+ else
+ return @names.join(".")
+ end
+ end
+ def lookup(locals)
+ if(@off_root)
+ local = locals.globals.space
+ else
+ local = locals.local
+ end
+ target = nil
+ while(!target && local)
+ target = test_lookup(local)
+ local = local.parent
+ end
+ return target if(target)
+ if(@off_root)
+ raise QError.new(<<ERROR_MSG)
+I was looking for .#{@names.join(".")}, but alas, it was not under
+\tthe root namespace.
+\tI'm really sorry old chap.
+\tWot. Wot.
+ERROR_MSG
+ else
+ raise QError.new(<<ERROR_MSG)
+I was looking for #{@names.join(".")}, but alas, I could not find
+\tit in #{locals.local.get_name} or any parent namespaces.
+\tI'm really sorry old chap.
+\tWot. Wot.
+ERROR_MSG
+ end
+ end
+ def self.parse(tokens)
+ names = []
+ off_root = (tokens.peak == :tDot)
+ tokens.next if(off_root)
+ names << tokens.expect(:tWord).data
+ while(tokens.peak == :tDot)
+ tokens.next
+ names << tokens.expect(:tWord).data
+ end
+ return self.new(names,off_root)
+ end
+end
diff --git a/aos/build/queues/objects/q_file.rb b/aos/build/queues/objects/q_file.rb
new file mode 100644
index 0000000..f683dda
--- /dev/null
+++ b/aos/build/queues/objects/q_file.rb
@@ -0,0 +1,148 @@
+class QStmt
+ def set_line(val)
+ @file_line = val
+ return self
+ end
+ def q_stack_name()
+ @file_line
+ end
+ def self.method_added(name)
+ @wrapped ||= {}
+ return if(name != :q_eval && name != :q_eval_extern)
+ return if(@wrapped[name])
+ @wrapped[name] = true
+ method = self.instance_method(name)
+ define_method(name) do |*args,&blk|
+ begin
+ method.bind(self).call(*args,&blk)
+ rescue QError => e
+ e.qstacktrace << self
+ raise e
+ end
+ end
+ end
+
+end
+class ImportStmt < QStmt
+ def initialize(filename)
+ @filename = filename
+ end
+ def q_eval(locals)
+ filename = locals.globals.find_file(@filename)
+ #puts "importing #{filename.inspect}"
+ q_file = QFile.parse(filename)
+ q_output = q_file.q_eval_extern(locals.globals)
+ q_output.extern = true
+ return Target::QInclude.new(@filename + ".h")
+ end
+ def self.parse(tokens)
+ line = tokens.pos
+ to_import = (tokens.expect(:tString) do |token|
+ <<ERROR_MSG
+I found a #{token.humanize} at #{token.pos}.
+\tI was really looking for a "filename" for this import statement.
+\tSomething like: import "super_cool_file";
+\tWot.Wot
+ERROR_MSG
+ end).data
+ tokens.expect(:tSemi) do |token|
+ <<ERROR_MSG
+I found a #{token.humanize} at #{token.pos}.
+\tI was really looking for a ";" to finish off this import statement
+\tat line #{line};
+\tSomething like: import #{to_import.inspect};
+\tWot.Wot #{" "*to_import.inspect.length}^
+ERROR_MSG
+ end
+ return self.new(to_import).set_line(line)
+ end
+end
+class PackageStmt < QStmt
+ def initialize(name)
+ @name = name
+ end
+ def q_eval(locals)
+ locals.package = @name
+ return nil
+ end
+ def self.parse(tokens)
+ line = tokens.pos
+ qualified_name = QualifiedName.parse(tokens)
+ tokens.expect(:tSemi)
+ return self.new(qualified_name).set_line(line)
+ end
+end
+class QFile
+ attr_accessor :namespace
+ def initialize(filename,suite)
+ @filename,@suite = filename,suite
+ end
+ def q_eval(globals = Globals.new())
+ local_pos = LocalSituation.new(globals)
+ q_file = Target::QFile.new()
+ @suite.each do |name|
+ val = name.q_eval(local_pos)
+ if(val)
+ if(val.respond_to?(:create))
+ q_file.add_type(val)
+ end
+ end
+ end
+ @namespace = local_pos.local
+ return q_file
+ end
+ def q_eval_extern(globals)
+ local_pos = LocalSituation.new(globals)
+ q_file = Target::QFile.new()
+ @suite.each do |name|
+ if(name.respond_to?(:q_eval_extern))
+ val = name.q_eval_extern(local_pos)
+ else
+ val = name.q_eval(local_pos)
+ end
+ if(val)
+ if(val.respond_to?(:create))
+ q_file.add_type(val)
+ end
+ end
+ end
+ return q_file
+ end
+ def self.parse(filename)
+ tokens = Tokenizer.new(filename)
+ suite = []
+ while(tokens.peak != :tEnd)
+ token = tokens.expect(:tWord) do |token| #symbol
+ <<ERROR_MSG
+I found a #{token.humanize} at #{token.pos}.
+\tI was really looking for a "package", "import", "queue_group",
+\t"message", or "queue" statement to get things moving.
+\tSomething like: import "super_cool_file";
+\tWot.Wot
+ERROR_MSG
+ end
+ case token.data
+ when "package"
+ suite << PackageStmt.parse(tokens)
+ when "import"
+ suite << ImportStmt.parse(tokens)
+ when "queue_group"
+ suite << QueueGroupStmt.parse(tokens)
+ when "message"
+ suite << MessageStmt.parse(tokens)
+ when "queue"
+ suite << QueueStmt.parse(tokens)
+ when "interface"
+ suite << InterfaceStmt.parse(tokens)
+ else
+ tokens.qError(<<ERROR_MSG)
+expected a "package","import","queue","queue_group", or "message" statement rather
+ than a #{token.data.inspect}, (whatever that is?)
+ oh! no! a feature request!?
+ Wot. Wot.
+ERROR_MSG
+ end
+ end
+ return self.new(filename,suite)
+ end
+end
diff --git a/aos/build/queues/objects/queue.rb b/aos/build/queues/objects/queue.rb
new file mode 100644
index 0000000..5693486
--- /dev/null
+++ b/aos/build/queues/objects/queue.rb
@@ -0,0 +1,154 @@
+class MessageElementStmt < QStmt
+ attr_accessor :name
+ def initialize(type,name,length = nil) #lengths are for arrays
+ @type = type
+ @name = name
+ @length = length
+ end
+ CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t"}
+ def check_type_error()
+ if(!(Sizes[@type] || (@length != nil && @type == "char")) )
+ if(correction = CommonMistakes[@type])
+ raise QError.new(<<ERROR_MSG)
+Hey! you have a \"#{@type}\" in your message statement.
+\tplease use #{correction} instead. Your type is not supported because we
+\twant to guarantee that the sizes of the messages stay the same across platforms.
+\tWot. Wot.
+ERROR_MSG
+ elsif(@type == "char")
+ raise QError.new(<<ERROR_MSG)
+Hey! you have a \"#{@type}\" in your message statement.
+\tyou need your declaration to be a char array like: char[10].
+\tor, please use int8_t or uint8_t.
+\tWot. Wot.
+ERROR_MSG
+ else
+ raise QError.new(<<ERROR_MSG)
+Hey! you have a \"#{@type}\" in your message statement.
+\tThat is not in the list of supported types.
+\there is the list of supported types:
+\tint{8,16,32,64}_t,uint{8,16,32,64}_t,bool,float,double#{len_comment}
+\tWot. Wot.
+ERROR_MSG
+ end
+ end
+ end
+
+ PrintFormat = {"bool" => "%c",
+ "float" => "%f",
+ "char" => "%c",
+ "double" => "%f",
+ "uint8_t" => "%\"PRIu8\"",
+ "uint16_t" => "%\"PRIu16\"",
+ "uint32_t" => "%\"PRIu32\"",
+ "uint64_t" => "%\"PRIu64\"",
+ "int8_t" => "%\"PRId8\"",
+ "int16_t" => "%\"PRId16\"",
+ "int32_t" => "%\"PRId32\"",
+ "int64_t" => "%\"PRId64\""}
+ def toPrintFormat()
+ if(format = PrintFormat[@type])
+ return format;
+ end
+ raise QError.new(<<ERROR_MSG)
+Somehow this slipped past me, but
+\tI couldn't find the print format of #{@type}. Really, my bad.
+\tWot. Wot.
+ERROR_MSG
+ end
+
+ Sizes = {"bool" => 1, "float" => 4,"double" => 8}
+ [8,16,32,64].each do |len|
+ Sizes["int#{len}_t"] = len / 8
+ Sizes["uint#{len}_t"] = len / 8
+ end
+ Zero = {"float" => "0.0f","double" => "0.0","bool" => "false"}
+ def size()
+ if(size = Sizes[@type]); return size; end
+ return 1 if(@type == "char")
+ raise QError.new(<<ERROR_MSG)
+Somehow this slipped past me, but
+\tI couldn't find the size of #{@type}. Really, my bad.
+\tWot. Wot.
+ERROR_MSG
+ end
+ def q_eval(locals)
+ check_type_error()
+ if(@length == nil)
+ member = Target::MessageElement.new(@type,@name)
+ else
+ member = Target::MessageArrayElement.new(@type,@name,@length)
+ end
+ member.size = size()
+ member.zero = Zero[@type] || "0";
+ member.printformat = toPrintFormat()
+ locals.local.add_member(member)
+ end
+ def self.parse(tokens)
+ line = tokens.pos
+ type = tokens.expect(:tWord).data
+ len = nil
+ if(tokens.peak == :tOpenB)
+ tokens.expect(:tOpenB)
+ len = tokens.expect(:tNumber).data
+ tokens.expect(:tCloseB)
+ end
+ name = tokens.expect(:tWord).data
+ tokens.expect(:tSemi)
+ return self.new(type,name,len).set_line(line)
+ end
+end
+class MessageStmt < QStmt
+ def initialize(name,suite)
+ @name = name
+ @suite = suite
+ end
+ def q_eval(locals)
+ group = Target::MessageDec.new(@name)
+ locals.register(group)
+ @suite.each do |stmt|
+ stmt.q_eval(locals.bind(group))
+ end
+ return group
+ end
+ def self.parse(tokens)
+ name = tokens.expect(:tWord).data
+ values = []
+ tokens.expect(:tOpenB)
+ while(tokens.peak != :tCloseB)
+ values << MessageElementStmt.parse(tokens)
+ end
+ names = {}
+ values.each do |val|
+ if(names[val.name])
+ raise QSyntaxError.new(<<ERROR_MSG)
+Hey! duplicate name #{val.name.inspect} in your message declaration statement (message #{name}).
+\tI found them at: #{names[val.name].q_stack_name()} and #{val.q_stack_name()}.
+\tWot. Wot.
+ERROR_MSG
+ end
+ names[val.name] = val
+ end
+ tokens.expect(:tCloseB)
+ tokens.expect(:tSemi)
+ self.new(name,values)
+ end
+end
+class QueueStmt < QStmt
+ def initialize(type,name)
+ @type,@name = type,name
+ end
+ def q_eval(locals)
+ queue = Target::QueueDec.new(@type.lookup(locals),@name)
+ locals.register(queue)
+ locals.local.add_queue(queue) if(locals.local.respond_to?(:add_queue))
+ return queue
+ end
+ def self.parse(tokens)
+ line = tokens.pos
+ type_name = QualifiedName.parse(tokens)
+ name = tokens.expect(:tWord).data
+ tokens.expect(:tSemi)
+ return self.new(type_name,name).set_line(line)
+ end
+end
diff --git a/aos/build/queues/objects/queue_group.rb b/aos/build/queues/objects/queue_group.rb
new file mode 100644
index 0000000..136834f
--- /dev/null
+++ b/aos/build/queues/objects/queue_group.rb
@@ -0,0 +1,115 @@
+class QueueGroupTypeStmt < QStmt
+ def initialize(name,suite)
+ @name,@suite = name,suite
+ end
+ def q_eval(locals)
+ group = Target::QueueGroupDec.new(@name)
+ group.created_by = self
+ locals.register(group)
+ @suite.each do |stmt|
+ stmt.q_eval(locals.bind(group))
+ end
+ return group
+ end
+end
+class ImplementsStmt < QStmt
+ def initialize(name)
+ @name = name
+ end
+ def q_eval(locals)
+
+ end
+ def self.parse(tokens)
+ name = QualifiedName.parse(tokens)
+ tokens.expect(:tSemi)
+ return self.new(name)
+ end
+end
+class QueueGroupStmt < QStmt
+ def initialize(type,name)
+ @type,@name = type,name
+ end
+ def q_eval(locals)
+ group = Target::QueueGroup.new(@type.lookup(locals),@name)
+ group.created_by = self
+ locals.register(group)
+ return group
+ end
+ def self.parse(tokens)
+ line = tokens.pos
+ type_name = QualifiedName.parse(tokens)
+ if(type_name.names.include?("queue_group"))
+ tokens.qError(<<ERROR_MSG)
+I was looking at the identifier you gave
+\tfor the queue group type between line #{line} and #{tokens.pos}
+\tThere shouldn't be a queue_group type called queue_group
+\tor including queue_group in it's path, it is a reserved keyword.
+\tWot. Wot.
+ERROR_MSG
+ end
+ if(tokens.peak == :tOpenB)
+ if(type_name.is_simple?())
+ type_name = type_name.to_simple
+ else
+ tokens.qError(<<ERROR_MSG)
+You gave the name: "#{type_name.to_s}" but you're only allowed to
+\thave simple names like "#{type_name.names[-1]}" in queue_group definitions
+\ttry something like:
+\tqueue_group ControlLoop { }
+\tWot. Wot.
+ERROR_MSG
+ end
+ tokens.expect(:tOpenB)
+ suite = []
+ while(tokens.peak != :tCloseB)
+ token = tokens.expect(:tWord) do |token|
+ <<ERROR_MSG
+I'm a little confused, I found a #{token.humanize} at #{token.pos}
+\tbut what I really wanted was an identifier signifying a nested
+\tmessage declaration, or queue definition, or an impliments statement.
+\tWot.Wot
+ERROR_MSG
+ end
+ case token.data
+ when "message"
+ suite << MessageStmt.parse(tokens)
+ when "queue"
+ suite << QueueStmt.parse(tokens)
+ when "implements"
+ suite << ImplementsStmt.parse(tokens)
+ else
+ tokens.qError(<<ERROR_MSG)
+expected a "queue","implements" or "message" statement rather
+\tthan a #{token.data.inspect}.
+\tWot. Wot.
+ERROR_MSG
+ end
+ end
+ tokens.expect(:tCloseB)
+ obj = QueueGroupTypeStmt.new(type_name,suite).set_line(line)
+ else
+ name = (tokens.expect(:tWord) do |token|
+ <<ERROR_MSG
+I found a #{token.humanize} at #{token.pos}
+\tbut I was in the middle of parsing a queue_group statement, and
+\twhat I really wanted was an identifier to store the queue group.
+\tSomething like: queue_group control_loops.Drivetrain my_cool_group;
+\tWot.Wot
+ERROR_MSG
+ end).data
+ obj = QueueGroupStmt.new(type_name,name).set_line(line)
+ if(tokens.peak == :tDot)
+ tokens.qError(<<ERROR_MSG)
+Hey! It looks like you're trying to use a complex identifier at: #{tokens.pos}
+\tThats not going to work. Queue Group definitions have to be of the form:
+\tqueue_group ComplexID SimpleID
+\tWot. Wot.
+ERROR_MSG
+ end
+ end
+ tokens.expect(:tSemi) do |token|
+ token.pos
+ end
+ return obj
+ end
+end
diff --git a/aos/build/queues/objects/tokenizer.rb b/aos/build/queues/objects/tokenizer.rb
new file mode 100644
index 0000000..2a33b90
--- /dev/null
+++ b/aos/build/queues/objects/tokenizer.rb
@@ -0,0 +1,213 @@
+class BufferedReader
+ def initialize(file)
+ @file = file
+ @line = 1
+ @chars = []
+ @col_nums = []
+ @col = 0
+ end
+ def filename
+ return File.basename(@file.path)
+ end
+ def pos()
+ "#{filename()}:#{lineno()},#{@col}"
+ end
+ def clear_comment()
+ @file.gets
+ @line += 1
+ end
+ def lineno()
+ return @line
+ return @file.lineno + 1
+ end
+ def pop_char()
+ val = @chars.pop() || @file.read(1)
+ @col_nums[@line] = @col += 1
+ if(val == "\n")
+ @line += 1
+ @col = 0
+ end
+
+ return val
+ end
+ def unpop_char(char)
+ if(char == "\n")
+ @line -= 1
+ @col = @col_nums[@line]
+ end
+ @col -= 1
+ @chars.push(char)
+ end
+end
+class Tokenizer
+ TOKEN_TYPES = {"{" => :tOpenB,"}"=> :tCloseB,";" => :tSemi,"," => :tComma,
+ "(" => :tOpenParan,")" => :tCloseParan,"=" => :tAssign,"." => :tDot,
+ "<<"=> :tLShift,"*" => :tMult,"+" => :tAdd,"[" => :tOpenB,
+ "]" => :tCloseB}
+ Humanize = TOKEN_TYPES.invert
+ class Token
+ attr_accessor :type,:data,:pos
+ def to_s
+ if(@type == :tString)
+ val = @data.inspect.to_s
+ elsif(@type == :tWord)
+ val = @data.to_s
+ else
+ val = @data.to_s
+ end
+ return "#{val.ljust(50)}:#{@type}"
+ end
+ def humanize()
+ if(@type == :tString)
+ return "#{@data.inspect.to_s} string"
+ elsif(@type == :tWord)
+ return "#{@data.inspect} identifier"
+ end
+ return Humanize[@type].inspect
+ end
+ def inspect()
+ data = ""
+ data = " #{@data.inspect}" if(@data)
+ "<Token :#{@type}#{data} at #{@pos}>"
+ end
+ def ==(other)
+ if(other.class == Symbol)
+ return @type == other
+ elsif(other.class == self.class)
+ return @type == other.type && @data == other.data
+ else
+ return nil
+ end
+ end
+ end
+ def initialize(file)
+ file = File.open(file,"r") if(file.class == String)
+ @read = BufferedReader.new(file)
+ end
+ def qError(error)
+ syntax_error(error)
+ end
+ def syntax_error(msg)
+ err = QSyntaxError.new(msg)
+ err.qstacktrace << "#{@read.lineno} of #{@read.filename}"
+ raise err
+ end
+ def peak_token()
+ @peak_token = next_token()
+ end
+ def peak()
+ peak_token()
+ end
+ def next()
+ next_token()
+ end
+ def pos()
+ @read.pos
+ end
+ def tokenize(string_token)
+ token = Token.new()
+ token.type = TOKEN_TYPES[string_token]
+ return token
+ end
+ def next_token()
+ if(token = @peak_token)
+ @peak_token = nil
+ return token
+ end
+ token = next_token_cache()
+ pos = self.pos()
+ token.pos = pos
+ return token
+ end
+ def next_token_cache()
+ token = Token.new()
+ token.data = ""
+ while (char = @read.pop_char())
+ #puts "#{char.inspect}:#{token.inspect}"
+ if(char == "/")
+ if(@read.pop_char == "/")
+ @read.clear_comment()
+ else
+ syntax_error("unexpected #{char.inspect}")
+ end
+ elsif(char == "#")
+ @read.clear_comment()
+ elsif(char =~ /[\s\r\n]/)
+ if(token.type)
+ return token
+ end
+ elsif(char =~ /\"/)
+ token.type = :tString
+ token.data = ""
+ while((char = @read.pop_char) != "\"")
+ token.data += char
+ end
+ return token
+ elsif(char =~ /[1-9]/)
+ token.type = :tNumber
+ token.data = char.to_i
+ while(char != ".")
+ char = @read.pop_char
+ if(char =~ /[0-9]/)
+ token.data = char.to_i + token.data * 10
+ elsif(char == ".")
+ else
+ @read.unpop_char(char)
+ return token
+ end
+ end
+ second_char = 0
+ man = 0
+ while(true)
+ char = @read.pop_char
+ if(char =~ /[0-9]/)
+ second_char = char.to_i + second_char * 10
+ man = man * 10
+ else
+ @read.unpop_char(char)
+ token.data += second_char / man.to_f
+ return token
+ end
+ end
+ elsif(char == ":")
+ if(@read.pop_char == "=")
+ return tokenize(":=")
+ end
+ syntax_error("unexpected \":\"")
+ elsif(char =~ /[;\{\}=()\",\*\+\.\[\]]/)
+ return(tokenize(char))
+ elsif(char =~ /[a-zA-Z_]/)
+ token.type = :tWord
+ token.data = char
+ while(true)
+ char = @read.pop_char()
+ if(char && char =~ /\w/)
+ token.data += char
+ else
+ @read.unpop_char(char)
+ return token
+ end
+ end
+ elsif(char == "<")
+ if((char = @read.pop_char()) == "<")
+ return tokenize("<<")
+ else
+ @read.unpop_char(char)
+ return tokenize("<")
+ end
+ else
+ syntax_error("unexpected #{char.inspect}")
+ end
+ end
+ token.type = :tEnd
+ return token
+ end
+ def expect(type,&blk)
+ token = self.next
+ if(token != type)
+ syntax_error(blk.call(token)) if(blk)
+ syntax_error("unexpected: #{token.type}")
+ end
+ return token
+ end
+end
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
new file mode 100644
index 0000000..0e957be
--- /dev/null
+++ b/aos/build/queues/output/message_dec.rb
@@ -0,0 +1,277 @@
+require "sha1"
+class Target::MessageDec < Target::Node
+ attr_accessor :name,:loc,:parent,:msg_hash
+ def initialize(name)
+ @name = name
+ @members = []
+ end
+ def extern=(value)
+ @extern=value
+ end
+ def get_name()
+ if(@parent)
+ return "#{@parent.get_name}.#{@name}"
+ else
+ return "#{@name}"
+ end
+ end
+ def add_member(member)
+ @members << member
+ end
+ def create_Print(type_class,cpp_tree)
+ member_func = CPP::MemberFunc.new(type_class,"size_t","Print")
+ type_class.add_member(member_func)
+ member_func.args << "char *buffer"
+ member_func.args << "size_t length"
+ member_func.const = true
+ format = "\""
+ args = []
+ @members.each do |elem|
+ format += ", "
+ format += elem.toPrintFormat()
+ if (elem.type == 'bool')
+ args.push("#{elem.name} ? 't' : 'f'")
+ else
+ args.push(elem.name)
+ end
+ end
+ format += "\""
+ member_func.suite << "size_t super_size = ::aos::Message::Print(buffer, length)"
+ member_func.suite << "buffer += super_size"
+ member_func.suite << "length -= super_size"
+ member_func.suite << "return super_size + snprintf(buffer, length, " + ([format] + args).join(", ") + ")";
+ end
+ def create_Serialize(type_class,cpp_tree)
+ member_func = CPP::MemberFunc.new(type_class,"size_t","Serialize")
+ type_class.add_member(member_func)
+ #cpp_tree.cc_file.add_funct(member_func)
+ member_func.args << "char *buffer"
+ member_func.suite << "::aos::Message::Serialize(buffer)"
+ member_func.const = true
+ offset = 0
+ @members.each do |elem|
+ elem.toNetwork(offset,member_func.suite)
+ offset += elem.size;
+ end
+ member_func.suite << "return Size()"
+ end
+ def create_Deserialize(type_class,cpp_tree)
+ member_func = CPP::MemberFunc.new(type_class,"size_t","Deserialize")
+ type_class.add_member(member_func)
+ #cpp_tree.cc_file.add_funct(member_func)
+ member_func.args << "const char *buffer"
+ member_func.suite << "::aos::Message::Deserialize(buffer)"
+ offset = 0
+ @members.each do |elem|
+ elem.toHost(offset,member_func.suite)
+ offset += elem.size;
+ end
+ member_func.suite << "return Size()"
+ end
+ def create_Zero(type_class,cpp_tree)
+ member_func = CPP::MemberFunc.new(type_class,"void","Zero")
+ type_class.add_member(member_func)
+ #cpp_tree.cc_file.add_funct(member_func)
+ @members.each do |elem|
+ elem.zeroCall(member_func.suite)
+ end
+ member_func.suite << "::aos::Message::Zero()"
+ end
+ def create_Size(type_class,cpp_tree)
+ member_func = CPP::MemberFunc.new(type_class,"size_t","Size")
+ member_func.inline = true
+ member_func.static = true
+ type_class.add_member(member_func.forward_dec)
+ #cpp_tree.cc_file.add_funct(member_func)
+ size = 0
+ @members.each do |elem|
+ size += elem.size
+ end
+ member_func.suite << CPP::Return.new(CPP::Add.new(size,
+ "::aos::Message::Size()"))
+ end
+ def self.builder_loc(loc)
+ return @builder_loc if(@builder_loc)
+ return @builder_loc = loc.root.get_make("aos")
+ end
+ def type_name(builder_loc,name)
+ if(builder_loc == @loc) #use relative name
+ return name
+ else #use full name
+ return @loc.to_cpp_id(name)
+ end
+ end
+ def create(cpp_tree)
+ return self if(@extern)
+ orig_namespace = namespace = cpp_tree.get(@loc)
+ name = ""
+ if(namespace.class < Types::Type) #is nested
+ name = namespace.name + "_" + name
+ namespace = namespace.space
+ end
+ type_class = namespace.add_struct(name + @name)
+ if(name.length > 0)
+ orig_namespace.add_member(:public, Types::TypeDef.new(type_class,@name))
+ end
+ cpp_tree.set(self,type_class)
+ type_class.set_parent("public ::aos::Message")
+ ts = (@members.collect { |elem|
+ elem.type + " " + elem.name
+ }).join(";")
+ self.msg_hash = "0x#{SHA1.hexdigest(ts)[-8..-1]}"
+ type_class.add_member("enum {kQueueLength = 1234, kHash = #{self.msg_hash}}")
+ @members.each do |elem|
+ type_class.add_member(elem.create_usage(cpp_tree))
+ end
+
+ create_Serialize(type_class,cpp_tree)
+ create_Deserialize(type_class,cpp_tree)
+ create_Zero(type_class,cpp_tree)
+ create_Size(type_class,cpp_tree)
+ create_Print(type_class,cpp_tree)
+
+ b_namespace = cpp_tree.get(b_loc = self.class.builder_loc(@loc))
+
+ safetemplate = Types::TemplateClass.new(b_namespace,"SafeMessageBuilder")
+ ifdef_statement = Types::PreprocessorIf.new(b_namespace,"!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)")
+ ifdef_statement.add_member(safetemplate)
+ b_namespace.add(ifdef_statement)
+ template = b_namespace.add_template("MessageBuilder")
+ safetemplate.spec_args << t = @loc.to_cpp_id(@name)
+ template.spec_args << t = @loc.to_cpp_id(@name)
+ safemsg_ptr_t = "SafeScopedMessagePtr< #{t}>"
+ msg_ptr_t = "ScopedMessagePtr< #{t}>"
+ safemsg_bld_t = "SafeMessageBuilder< #{t}>"
+ msg_bld_t = "MessageBuilder< #{t}>"
+ safetemplate.add_member(:private,"#{safemsg_ptr_t} msg_ptr_")
+ template.add_member(:private,"#{msg_ptr_t} msg_ptr_")
+ namespace.add_pre_swig("%feature(\"valuewrapper\") #{safemsg_bld_t}")
+ template.add_member(:private,"#{msg_bld_t}(const #{msg_bld_t}&)")
+ template.add_member(:private,"void operator=(const #{msg_bld_t}&)")
+ safetemplate.add_member(:private,"friend class ::aos::Queue< #{t}>")
+ template.add_member(:private,"friend class ::aos::Queue< #{t}>")
+
+ cons = CPP::Constructor.new(template)
+ unsafe_cons = CPP::Constructor.new(template)
+ cons_ifdef_statement = CPP::PreprocessorIf.new(cons, unsafe_cons)
+ cons_ifdef_statement.name = "!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)"
+ template.add_member(:private,cons_ifdef_statement)
+ cons.args << "aos_queue *queue"
+ cons.args << "#{t} *msg"
+ unsafe_cons.args << "#{t} *msg"
+ cons.add_cons("msg_ptr_","queue","msg")
+ unsafe_cons.add_cons("msg_ptr_","msg")
+ cons = safetemplate.add_member(:private,CPP::Constructor.new(safetemplate))
+ cons.args << "aos_queue *queue"
+ cons.add_cons("msg_ptr_","queue")
+ safetemplate.public
+ template.public
+ DefineMembers(cpp_tree, safetemplate, safemsg_bld_t)
+ DefineMembers(cpp_tree, template, msg_bld_t)
+
+ java_type_name = java_type_name(cpp_tree)
+ namespace.add_post_swig("%template(#{java_type_name}) ::aos::Queue< #{t}>")
+ namespace.add_post_swig("%template(#{java_ptr_name(cpp_tree)}) ::aos::SafeScopedMessagePtr< #{t}>")
+ namespace.add_post_swig("%template(#{java_builder_name(cpp_tree)}) ::aos::SafeMessageBuilder< #{t}>")
+ # TODO(aschuh): Figure out why this doesn't work and fix it.
+ #namespace.add_post_swig("%typemap(javabase) #{@name} \"aos.Message\"")
+
+ end
+ def DefineMembers(cpp_tree, template, msg_bld_t)
+ send = template.def_func("bool","Send")
+ send.suite << CPP::Return.new("msg_ptr_.Send()")
+ @members.each do |elem|
+=begin
+ MessageBuilder<frc971::control_loops::Drivetrain::Goal> &steering(
+ double steering) {
+ msg_ptr_->steering = steering;
+ return *this;
+ }
+=end
+ setter = template.def_func(msg_bld_t,"&#{elem.name}")
+ setter.args << elem.create_usage(cpp_tree)
+ elem.set_message_builder(setter.suite)
+ setter.suite << CPP::Return.new("*this")
+
+ end
+ end
+ def java_ptr_name(cpp_tree)
+ return "#{@name}MessagePtr"
+ end
+ def java_builder_name(cpp_tree)
+ return "#{@name}MessageBuilder"
+ end
+ def java_type_name(cpp_tree)
+ return "#{@name}Queue"
+ end
+end
+class Target::MessageElement < Target::Node
+ attr_accessor :name,:loc,:size,:zero,:type,:printformat
+ def initialize(type,name)
+ @type,@name = type,name
+ end
+ def toPrintFormat()
+ return printformat
+ end
+ def create_usage(cpp_tree)
+ "#{@type} #{@name}"
+ end
+ def toNetwork(offset,suite)
+ offset = (offset == 0) ? "" : "#{offset} + "
+ suite << f_call = CPP::FuncCall.build("to_network",
+ "&#{@name}",
+ "&buffer[#{offset}::aos::Message::Size()]")
+ f_call.args.dont_wrap = true
+ end
+ def toHost(offset,suite)
+ offset = (offset == 0) ? "" : "#{offset} + "
+ suite << f_call = CPP::FuncCall.build("to_host",
+ "&buffer[#{offset}::aos::Message::Size()]",
+ "&#{@name}")
+ f_call.args.dont_wrap = true
+ end
+ def set_message_builder(suite)
+ suite << "msg_ptr_->#{@name} = #{@name}"
+ end
+
+ def zeroCall(suite)
+ suite << CPP::Assign.new(@name,@zero)
+ end
+end
+class Target::MessageArrayElement < Target::Node
+ attr_accessor :name,:loc,:size,:zero,:type
+ def initialize(type,name,length)
+ @type,@name,@length = type,name,length
+ end
+ def create_usage(cpp_tree)
+ "#{@type} #{@name}[#@length]"
+ end
+ def type()
+ "#{@type}[#@length]"
+ end
+ def size()
+ @size * @length
+ end
+ def toNetwork(offset,suite)
+ offset = (offset == 0) ? "" : "#{offset} + "
+ suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
+ for_stmt.suite << f_call = CPP::FuncCall.build("to_network",
+ "&(#{@name}[i])",
+ "&buffer[i + #{offset}::aos::Message::Size()]")
+ f_call.args.dont_wrap = true
+ end
+ def toHost(offset,suite)
+ offset = (offset == 0) ? "" : "#{offset} + "
+ suite << for_stmt = CPP::For.new("int i = 0","i < #{@length}","i++")
+ for_stmt.suite << f_call = CPP::FuncCall.build("to_host",
+ "&buffer[i + #{offset}::aos::Message::Size()]",
+ "&(#{@name}[i])")
+ f_call.args.dont_wrap = true
+ end
+ def set_message_builder(suite)
+ suite << "memcpy(msg_ptr_->#{@name},#{@name},#@length)"
+ end
+ def zeroCall(suite)
+ suite << "memset(#@name,0,#{size()})"
+ end
+end
diff --git a/aos/build/queues/output/q_file.rb b/aos/build/queues/output/q_file.rb
new file mode 100644
index 0000000..af76ee1
--- /dev/null
+++ b/aos/build/queues/output/q_file.rb
@@ -0,0 +1,187 @@
+require "sha1"
+module Target
+end
+class Target::Node
+ attr_accessor :created_by
+end
+class Target::QFile < Target::Node
+ def initialize() #needs to know repo_path,
+ @class_types = []
+ end
+ def add_type(type)
+ @class_types << type
+ end
+ def extern=(value)
+ @class_types.each do |type|
+ type.extern=value
+ end
+ end
+ def make_cpp_tree(rel_path)
+ cpp_tree = DepFilePair.new(rel_path)
+ cpp_tree.add_header_include("\"aos/common/macros.h\"")
+ cpp_tree.add_header_include("\"aos/common/queue.h\"")
+ @class_types.each do |type|
+ cpp_tree.get(type)
+ end
+ return cpp_tree
+ end
+end
+class Target::QInclude < Target::Node
+ def initialize(path)
+ @path = path
+ end
+ def create(cpp_tree)
+# inc = cpp_tree.header.add_include("\"#{@path}\"")
+ inc = cpp_tree.add_header_include("\"#{@path}\"")
+ cpp_tree.set(self,inc)
+ end
+end
+class Target::QueueGroupDec < Target::Node
+ attr_accessor :name,:loc,:parent,:queues
+ def initialize(name)
+ @name = name
+ @queues = []
+ @subs = {}
+ end
+ def root()
+ @parent.root()
+ end
+ def []=(key,val)
+ #puts "#{key}= #{val}"
+ @subs[key] = val
+ end
+ def extern=(value)
+ @extern=value
+ end
+ def get_name()
+ if(@parent)
+ return "#{@parent.get_name}.#{@name}"
+ else
+ return "#{@name}"
+ end
+ end
+ def to_cpp_id(id)
+ name = "#{@name}::#{id}"
+ return @parent.to_cpp_id(name) if(@parent)
+ return name
+ end
+ def [](key)
+ #puts "#{key}"
+ @subs[key]
+ end
+ def add_queue(queue)
+ @queues.push(queue)
+ end
+ def hash_with_name(name)
+ ts = (@queues.collect { |queue|
+ queue.msg_hash()
+ }).join("") + name
+ return "0x#{SHA1.hexdigest(ts)[-8..-1]}"
+ end
+ def create(cpp_tree)
+ return if(@extern)
+ namespace = cpp_tree.get(@loc)
+ type_class = Types::Class.new(namespace,@name)
+ cpp_tree.set(self,type_class) #breaks infinite recursion
+ type_class.set_parent("public ::aos::QueueGroup")
+ @queues.each do |queue|
+ type_class.add_member(:public,queue.create_usage(cpp_tree))
+ namespace.add_pre_swig("%immutable #{@name}::#{queue.name}")
+ end
+ create_Constructor(type_class,cpp_tree)
+ namespace.add(type_class)
+ end
+ def create_Constructor(type_class,cpp_tree)
+ member_func = CPP::Constructor.new(type_class)
+ type_class.add_member(:public,member_func)
+ #cpp_tree.cc_file.add_funct(member_func)
+ member_func.args << "const char *name";
+ member_func.args << "uint32_t hash";
+ member_func.add_cons("::aos::QueueGroup","name", "hash")
+ @queues.each do |queue|
+ member_func.args << "const char *#{queue.name}_name";
+ member_func.add_cons(queue.name,"#{queue.name}_name")
+ end
+ end
+end
+class Target::QueueGroup < Target::Node
+ attr_accessor :name,:loc
+ def initialize(type,name)
+ @type,@name = type,name
+ end
+ def type_name()
+ if(@type.loc == @loc) #use relative name
+ return @type.name
+ else #use full name
+ return @type.loc.to_cpp_id(@type.name)
+ end
+ end
+ def create(cpp_tree)
+ namespace = cpp_tree.get(@loc)
+ type = cpp_tree.get(@type)
+ cpp_tree.set(self,self)
+ namespace.add_cc("static #{type_name} *#{@name}_ptr")
+ counter = "#{@name}_counter"
+ namespace.add_cc("static int #{counter}")
+
+ str = <<COMMENT_END
+Schwarz counter to construct and destruct the #{@name} object.
+Must be constructed before &#{@name} is constructed so that #{@name}_ptr
+is valid so we can store a reference to the object.
+COMMENT_END
+ str.split(/\n/).each do |str_sec|
+ namespace.class_comment(str_sec)
+ end
+ init_class = namespace.add_class("InitializerFor_" + @name).add_dep(type)
+
+
+ init_class.add_cc_comment(
+ "The counter is initialized at load-time, i.e., before any of the static",
+ "objects are initialized.")
+
+
+ cons = CPP::Constructor.new(init_class)
+ init_class.add_member(:public,cons)
+ cons.suite << if_stmt = CPP::If.new("0 == #{counter}++")
+ if_stmt.suite << "printf(#{"making a #{@name}!\n".inspect})"
+
+ cons_call = CPP::FuncCall.new("new #{type_name}")
+ cons_call.args.push(@loc.queue_name(@name).inspect)
+
+ cons_call.args.push(@type.hash_with_name(@loc.queue_name(@name).inspect))
+ @type.queues.collect do |queue|
+ cons_call.args.push(@loc.queue_name(@name + "." + queue.name).inspect)
+ end
+ if_stmt.suite << CPP::Assign.new("#{@name}_ptr",cons_call)
+ if_stmt.else_suite << CPP::FuncCall.build("printf","already made a #{@name}\n".inspect)
+
+
+ destruct = CPP::Destructor.new(init_class)
+ destruct.suite << if_stmt = CPP::If.new("0 == --#{counter}")
+ if_stmt.suite << "printf(#{"deleting a #{@name}!! :) !!\n".inspect})"
+ if_stmt.suite << "delete #{@name}_ptr"
+ if_stmt.suite << CPP::Assign.new("#{@name}_ptr","NULL")
+
+ init_class.add_member(:public,destruct)
+ init_class.static = true
+ init_class.dec = @name + "_initializer";
+
+ str = <<COMMENT_END
+Create a reference to the new object in the pointer. Since we have already
+created the initializer
+COMMENT_END
+ comments = str.split(/\n/).map{|str_sec| CPP::Comment.new(str_sec)}
+ comments << "static UNUSED_VARIABLE #{type_name} &#{@name} = " +
+ "#{@name}_initializer.get()"
+ namespace.add_post_swig("%immutable #{@name}_initializer")
+ namespace.add_post_swig(CPP::SwigPragma.new("java", "modulecode", CPP::Suite.new(["public static final #{@name} = get#{@name.capitalize}_initializer().get()"])))
+ ifdef_statement = CPP::IfnDef.new(CPP::Suite.new(comments))
+ ifdef_statement.name = "SWIG"
+ namespace.add(ifdef_statement)
+
+
+ get = init_class.def_func(type_name,"get") #.add_dep(type)
+ get.pre_func_types = "&"
+ get.suite << CPP::Return.new("*#{@name}_ptr")
+ end
+end
diff --git a/aos/build/queues/output/queue_dec.rb b/aos/build/queues/output/queue_dec.rb
new file mode 100644
index 0000000..8c3bd51
--- /dev/null
+++ b/aos/build/queues/output/queue_dec.rb
@@ -0,0 +1,104 @@
+class Target::QueueDec < Target::Node
+ attr_accessor :name,:loc
+ def initialize(type,name)
+ @type,@name = type,name
+ end
+ def msg_hash()
+ return @type.msg_hash
+ end
+ def java_type_name(cpp_tree)
+ type = cpp_tree.get(@type)
+ return "#{type.name}Queue"
+ end
+ def full_message_name(cpp_tree)
+ type = cpp_tree.get(@type)
+ return @type.loc.to_cpp_id(type.name)
+ end
+ def full_ptr_name(cpp_tree)
+ return "::aos::SafeScopedMessagePtr< #{full_message_name(cpp_tree)}>"
+ end
+ def full_builder_name(cpp_tree)
+ return "::aos::MessageBuilder< #{full_message_name(cpp_tree)}>"
+ end
+ def full_type_name(cpp_tree)
+ return "::aos::Queue< #{full_message_name(cpp_tree)}>"
+ end
+ def type_name(cpp_tree,queue_type = "::aos::Queue")
+ type = cpp_tree.get(@type)
+ if(@type.loc == @loc) #use relative name
+ return "#{queue_type}<#{type.name}>"
+ else #use full name
+ return "#{queue_type}< #{@type.loc.to_cpp_id(type.name)}>"
+ end
+ end
+ def create_usage(cpp_tree)
+ "#{type_name(cpp_tree)} #{@name}"
+ end
+ def create(cpp_tree)
+ namespace = cpp_tree.get(@loc)
+ type = cpp_tree.get(@type)
+ cpp_tree.set(self,self)
+ type_name = type_name(cpp_tree)
+ full_type_name = full_type_name(cpp_tree)
+ namespace.add_cc("static #{type_name} *#{@name}_ptr")
+ counter = "#{@name}_counter"
+ namespace.add_cc("static int #{counter}")
+
+ str = <<COMMENT_END
+Schwarz counter to construct and destruct the #{@name} queue.
+Must be constructed before &#{@name} is constructed so that #{@name}_ptr
+is valid so we can store a reference to the object.
+COMMENT_END
+ str.split(/\n/).each do |str_sec|
+ namespace.class_comment(str_sec)
+ end
+ init_class = namespace.add_class("InitializerFor_" + @name)
+
+ init_class.add_cc_comment(
+ "The counter is initialized at load-time, i.e., before any of the static",
+ "objects are initialized.")
+
+
+ cons = CPP::Constructor.new(init_class)
+ init_class.add_member(:public,cons)
+ cons.suite << if_stmt = CPP::If.new("0 == #{counter}++")
+ if_stmt.suite << "printf(#{"making a #{@name} queue!\n".inspect})"
+
+ cons_call = CPP::FuncCall.new("new #{type_name}")
+ cons_call.args.push(@loc.queue_name(@name).inspect)
+ if_stmt.suite << CPP::Assign.new("#{@name}_ptr",cons_call)
+ if_stmt.else_suite << CPP::FuncCall.build("printf","already made a #{@name}\n".inspect)
+
+
+ destruct = CPP::Destructor.new(init_class)
+ init_class.add_member(:public,destruct)
+ destruct.suite << if_stmt = CPP::If.new("0 == --#{counter}")
+ if_stmt.suite << "printf(#{"deleting a #{@name}!! :) !!\n".inspect})"
+ if_stmt.suite << "delete #{@name}_ptr"
+ if_stmt.suite << CPP::Assign.new("#{@name}_ptr","NULL")
+
+ init_class.static = true
+ init_class.dec = @name + "_initializer";
+
+ str = <<COMMENT_END
+Create a reference to the new object in the pointer. Since we have already
+created the initializer
+COMMENT_END
+ comments = str.split(/\n/).map{|str_sec| CPP::Comment.new(str_sec)}
+ comments << "static UNUSED_VARIABLE #{type_name} &#{@name} = " +
+ "#{@name}_initializer.get()"
+ namespace.add_post_swig("%immutable #{@name}_initializer")
+ java_type_name = java_type_name(cpp_tree)
+ namespace.add_post_swig(CPP::SwigPragma.new("java", "modulecode", CPP::Suite.new(["public static final #{java_type_name} #{@name} = get#{@name.capitalize}_initializer().get()"])))
+
+ ifdef_statement = CPP::IfnDef.new(CPP::Suite.new(comments))
+ ifdef_statement.name = "SWIG"
+ namespace.add(ifdef_statement)
+
+ get = init_class.def_func(full_type_name,"get")
+ get.pre_func_types = "&"
+ get.suite << CPP::Return.new("*#{@name}_ptr")
+
+ end
+end
+
diff --git a/aos/build/swig.gypi b/aos/build/swig.gypi
new file mode 100644
index 0000000..2e99a95
--- /dev/null
+++ b/aos/build/swig.gypi
@@ -0,0 +1,73 @@
+# Include this file in any target that needs to use swig wrappers.
+#
+# To use, create a target of the following form:
+# {
+# 'target_name': 'my_target_javawrap',
+# 'type': 'static_library', # or any other type that can handle .cc files
+# 'sources': [
+# 'aos/example/target.swig',
+# ],
+# 'variables': {
+# 'package': 'aos.test',
+# },
+# 'includes': ['path/to/swig.gypi'],
+# },
+# Code that depends on this target will be able to use the swig wrapped
+# java classes.
+#
+# using <http://src.chromium.org/svn/trunk/src/build/protoc.gypi> as an
+# example of how this should work
+{
+ 'variables': {
+ 'prefix_dir': '<(SHARED_INTERMEDIATE_DIR)/',
+ 'out_dir': '<(prefix_dir)/<(_target_name)/',
+ 'output_java_wrap': '<(out_dir)/<(RULE_INPUT_ROOT)_wrap.cc',
+ 'java_dir': '<(out_dir)/<(RULE_INPUT_ROOT)_java',
+ 'no_rsync': 1,
+ },
+ 'rules': [
+ {
+ 'rule_name': 'genswig',
+ 'extension': 'swig',
+ 'outputs': [
+ '<(output_java_wrap)',
+ '<(java_dir)',
+ ],
+ 'action': [
+ '<(DEPTH)/aos/build/mkdirswig',
+ '<(java_dir)',
+ '-I<(DEPTH)',
+ '-outdir', ' <(java_dir)',
+ '-package', '<(package)',
+ '-o', '<(output_java_wrap)',
+ '-c++',
+ '-Wall',
+ '-Wextra',
+ '-java',
+ '<(RULE_INPUT_PATH)'],
+ 'message': 'Generating C++ code from <(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT).swig',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ 'cflags': [
+# For the swig-generated C++ code.
+ '-fno-strict-aliasing',
+ '-Wno-cast-qual',
+ ],
+ 'include_dirs': [
+ '<(prefix_dir)/<(_target_name)',
+ '/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/default-java/include/linux',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<(prefix_dir)/<(_target_name)',
+ '/usr/lib/jvm/default-java/include',
+ '/usr/lib/jvm/default-java/include/linux',
+ ],
+ 'variables': {
+ 'gen_srcdir_parents': ['<(out_dir)'],
+ },
+ },
+ 'hard_dependency': 1,
+}