From 319b258fcb7c9b131d0c6430ec771fb486d4cb0b Mon Sep 17 00:00:00 2001 From: apla Date: Mon, 2 Feb 2015 02:35:46 +0300 Subject: [PATCH] completion current state --- completion/CodeComplete/CodeComplete.cc | 198 ++++++++++++++++++ completion/CodeComplete/Makefile | 29 +++ completion/CodeComplete/README.md | 1 + completion/CodeComplete/libclang-c.sh | 2 + completion/CodeComplete/libclang-node.sh | 2 + completion/CodeComplete/walker.js | 80 ++++++++ completion/arduino-test-clang/Arduino.h | 249 +++++++++++++++++++++++ completion/arduino-test-clang/test.cpp | 9 + node/clang-domain.js | 163 +++++++++++++++ node/clang-project.js | 164 +++++++++++++++ node/walk-source.js | 64 ++++++ 11 files changed, 961 insertions(+) create mode 100644 completion/CodeComplete/CodeComplete.cc create mode 100644 completion/CodeComplete/Makefile create mode 100644 completion/CodeComplete/README.md create mode 100755 completion/CodeComplete/libclang-c.sh create mode 100755 completion/CodeComplete/libclang-node.sh create mode 100644 completion/CodeComplete/walker.js create mode 100644 completion/arduino-test-clang/Arduino.h create mode 100644 completion/arduino-test-clang/test.cpp create mode 100644 node/clang-domain.js create mode 100644 node/clang-project.js create mode 100644 node/walk-source.js diff --git a/completion/CodeComplete/CodeComplete.cc b/completion/CodeComplete/CodeComplete.cc new file mode 100644 index 0000000..8f3e2b8 --- /dev/null +++ b/completion/CodeComplete/CodeComplete.cc @@ -0,0 +1,198 @@ +#include +#include +#include + +const char *_getCompleteChunkKindSpelling(CXCompletionChunkKind chunkKind) { + switch (chunkKind) { + case CXCompletionChunk_Optional: return "Optional"; break; + case CXCompletionChunk_TypedText: return "TypedText"; break; + case CXCompletionChunk_Text: return "Text"; break; + case CXCompletionChunk_Placeholder: return "Placeholder"; break; + case CXCompletionChunk_Informative: return "Informative"; break; + case CXCompletionChunk_CurrentParameter: return "CurrentParameter"; break; + case CXCompletionChunk_LeftParen: return "LeftParen"; break; + case CXCompletionChunk_RightParen: return "RightParen"; break; + case CXCompletionChunk_LeftBracket: return "LeftBracket"; break; + case CXCompletionChunk_RightBracket: return "RightBracket"; break; + case CXCompletionChunk_LeftBrace: return "LeftBrace"; break; + case CXCompletionChunk_RightBrace: return "RightBrace"; break; + case CXCompletionChunk_LeftAngle: return "LeftAngle"; break; + case CXCompletionChunk_RightAngle: return "RightAngle"; break; + case CXCompletionChunk_Comma: return "Comma"; break; + case CXCompletionChunk_ResultType: return "ResultType"; break; + case CXCompletionChunk_Colon: return "Colon"; break; + case CXCompletionChunk_SemiColon: return "SemiColon"; break; + case CXCompletionChunk_Equal: return "Equal"; break; + case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; break; + case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; break; + default: return "Unknown"; break; + } +} + +const char *_getCompletionAvailabilitySpelling(CXAvailabilityKind availavility) { + switch (availavility) { + case CXAvailability_Available: return "Available"; break; + case CXAvailability_Deprecated: return "Deprecated"; break; + case CXAvailability_NotAvailable: return "NotAvailable"; break; + case CXAvailability_NotAccessible: return "NotAccessible"; break; + default: return "Unknown"; break; + } +} + +const char *_getKindTypeName(CXCursor cursor) { + CXCursorKind curKind = clang_getCursorKind(cursor); + const char *type; + if (clang_isAttribute(curKind)) { + type = "Attribute"; + } else if (clang_isDeclaration(curKind)) { + type = "Declaration"; + } else if (clang_isExpression(curKind)) { + type = "Expression"; + } else if (clang_isInvalid(curKind)) { + type = "Invalid"; + } else if (clang_isPreprocessing(curKind)) { + type = "Preprocessing"; + } else if (clang_isReference(curKind)) { + type = "Reference"; + } else if (clang_isStatement(curKind)) { + type = "Statement"; + } else if (clang_isTranslationUnit(curKind)) { + type = "TranslationUnit"; + } else if (clang_isUnexposed(curKind)) { + type = "Unexposed"; + } else { + type = "Unknown"; + } + return type; +} + +void show_completion_results(CXCodeCompleteResults *compResults) { + printf("=== show results ===\n"); + unsigned isIncomplete; + CXCursorKind kind = clang_codeCompleteGetContainerKind(compResults, &isIncomplete); + printf("Complete: %d\n", !isIncomplete); + CXString kindName = clang_getCursorKindSpelling(kind); + printf("Kind: %s\n", clang_getCString(kindName)); + clang_disposeString(kindName); + + CXString usr = clang_codeCompleteGetContainerUSR(compResults); + printf("USR: %s\n", clang_getCString(usr)); + clang_disposeString(usr); + + unsigned long long context = clang_codeCompleteGetContexts(compResults); + printf("Context: %llu\n", context); + printf("\n"); + + // show completion results + printf("=== show completion results ===\n"); + printf("CodeCompleationResultsNum: %d\n", compResults->NumResults); + for (auto i = 0U; i < compResults->NumResults; i++) { + printf("Results: %d\n", i); + const CXCompletionResult &result = compResults->Results[i]; + const CXCompletionString &compString = result.CompletionString; + const CXCursorKind kind = result.CursorKind; + + CXString kindName = clang_getCursorKindSpelling(kind); + printf(" Kind: %s\n", clang_getCString(kindName)); + clang_disposeString(kindName); + + CXAvailabilityKind availavility = clang_getCompletionAvailability(compString); + const char *availavilityText = _getCompletionAvailabilitySpelling(availavility); + printf(" Availavility: %s\n", availavilityText); + + unsigned priority = clang_getCompletionPriority(compString); + printf(" Priority: %d\n", priority); + + CXString comment = clang_getCompletionBriefComment(compString); + printf(" Comment: %s\n", clang_getCString(comment)); + clang_disposeString(comment); + + unsigned numChunks = clang_getNumCompletionChunks(compString); + printf(" NumChunks: %d\n", numChunks); + for (auto j = 0U; j < numChunks; j++) { + CXString chunkText = clang_getCompletionChunkText(compString, j); + CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(compString, j); + printf(" Kind: %s Text: %s\n", + _getCompleteChunkKindSpelling(chunkKind), + clang_getCString(chunkText)); + + // TODO: check child chunks when CXCompletionChunk_Optional + // CXCompletionString child = clang_getCompletionChunkCompletionString(compString); + clang_disposeString(chunkText); + } + + unsigned numAnnotations = clang_getCompletionNumAnnotations(compString); + printf(" NumAnnotation: %d\n", numAnnotations); + for (auto j = 0U; j < numAnnotations; j++) { + CXString annoText = clang_getCompletionAnnotation(compString, j); + printf(" Annotation: %s\n", clang_getCString(annoText)); + clang_disposeString(annoText); + } + printf("\n"); + } +} + +void show_diagnosis(const CXTranslationUnit &tu, + CXCodeCompleteResults *compResults) { + printf("=== show diagnosis ===\n"); + unsigned numDiag = clang_codeCompleteGetNumDiagnostics(compResults); + printf("NumDiagnosis:%d\n", numDiag); + for (auto i = 0U; i < numDiag; i++) { + clang_codeCompleteGetDiagnostic(compResults, i); + CXDiagnostic diag = clang_getDiagnostic(tu, i); + CXString diagText = clang_getDiagnosticSpelling(diag); + printf(" Diagnosis: %s\n", clang_getCString(diagText)); + clang_disposeString(diagText); + } +} + +void show_clang_version(void) { + CXString version = clang_getClangVersion(); + printf("%s\n", clang_getCString(version)); + clang_disposeString(version); +} + +int main(int argc, char **argv) { + if (argc < 4) { + printf("CodeComplete filename line column [options ...]\n"); + exit(1); + } + + show_clang_version(); + + const auto filename = argv[1]; + unsigned lineno = atoi(argv[2]); + unsigned columnno = atoi(argv[3]); + const auto cmdArgs = &argv[4]; + auto numArgs = argc - 4; + + // create index w/ excludeDeclsFromPCH = 1, displayDiagnostics=1. + CXIndex index = clang_createIndex(1, 0); + + // create Translation Unit + CXTranslationUnit tu = clang_parseTranslationUnit(index, filename, cmdArgs, numArgs, NULL, 0, CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_Incomplete ); + if (tu == NULL) { + printf("Cannot parse translation unit\n"); + exit(1); + } + + // Code Completion + CXCodeCompleteResults *compResults; + compResults = clang_codeCompleteAt(tu, filename, lineno, columnno, + NULL, 0, clang_defaultCodeCompleteOptions()); + if (compResults == NULL) { + printf("Invalid\n"); + exit(1); + } + + // show Completion results + show_completion_results(compResults); + + // show Diagnosis + show_diagnosis(tu, compResults); + + clang_disposeCodeCompleteResults(compResults); + clang_disposeTranslationUnit(tu); + clang_disposeIndex(index); + return 0; +} diff --git a/completion/CodeComplete/Makefile b/completion/CodeComplete/Makefile new file mode 100644 index 0000000..dd332e4 --- /dev/null +++ b/completion/CodeComplete/Makefile @@ -0,0 +1,29 @@ + +UNAME_S:=$(shell uname -s) + +TARGET=CodeComplete +CXX=clang +CFLAGS=-std=c++11 -O2 -Wall -Wextra +ifeq ($(UNAME_S), Darwin) +CLANG_STDLIB:=-stdlib=libstdc++ +CFLAGS+=$(CLANG_STDLIB) +endif +FLAGS=`llvm-config --cxxflags --ldflags` -lclang $(CFLAGS) + +SAMPLE_DIR=samples +SAMPLES:=$(wildcard $(SAMPLE_DIR)/*.cc) +SAMPLES_OUT:=$(subst .cc,_out.txt,$(SAMPLES)) + +all: $(TARGET) + +$(TARGET): $(TARGET).cc + $(CXX) $(TARGET).cc -o $(TARGET) $(FLAGS) + +run: $(SAMPLES_OUT) + +$(SAMPLE_DIR)/%_out.txt: $(TARGET) + -./$(TARGET) $(SAMPLE_DIR)/$*.cc $(shell echo $* | sed 's/.*_l\([0-9][0-9]*\)c\([0-9][0-9]*\).*/\1 \2/') $(CLANG_STDLIB) > $@ 2>&1 + +clean: + @find . -name '*~' | xargs rm -f + @rm -f $(TARGET) $(SAMPLES_OUT) diff --git a/completion/CodeComplete/README.md b/completion/CodeComplete/README.md new file mode 100644 index 0000000..8f31c6b --- /dev/null +++ b/completion/CodeComplete/README.md @@ -0,0 +1 @@ +sample taken from: https://github.com/sabottenda/libclang-sample diff --git a/completion/CodeComplete/libclang-c.sh b/completion/CodeComplete/libclang-c.sh new file mode 100755 index 0000000..7f1d9c0 --- /dev/null +++ b/completion/CodeComplete/libclang-c.sh @@ -0,0 +1,2 @@ +#!/bin/sh +DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./ ./CodeComplete samples/sample2_l6c9.cc 6 9 diff --git a/completion/CodeComplete/libclang-node.sh b/completion/CodeComplete/libclang-node.sh new file mode 100755 index 0000000..237a256 --- /dev/null +++ b/completion/CodeComplete/libclang-node.sh @@ -0,0 +1,2 @@ +#!/bin/sh +NODE_PATH=/Users/apla/work/mcu/brackets-cuwire/node/node_modules node walker.js diff --git a/completion/CodeComplete/walker.js b/completion/CodeComplete/walker.js new file mode 100644 index 0000000..c07214d --- /dev/null +++ b/completion/CodeComplete/walker.js @@ -0,0 +1,80 @@ +var libclang = require('libclang'); +var Index = libclang.Index; +var Cursor = libclang.Cursor; +var TranslationUnit = libclang.TranslationUnit; + +var index = new Index(true, true); + +// DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:clang NODE_PATH=/Users/apla/work/mcu/brackets-cuwire/node/node_modules node walk-source.js | less + +//var source = "/var/folders/r4/d4l8c_ts4rsdc670pdkbtr0m0000gp/T/Sensor-cuwire-5358ae5d/Sensor.cpp"; +var source = 'samples/sample2_l6c9.cc'; + +var tu = TranslationUnit.parse ( + index, + source, [ + "-Wno-unknown-attributes", + // "-fsyntax-only", +// "-nostdinc", +// // "-nostdlibinc", +// // "-nobuiltininc", +// "-MMD", +// "-xc++", +// "-DF_CPU=16000000L", +// "-DARDUINO=158", +// "-DARDUINO_AVR_PRO", +// "-DARDUINO_ARCH_AVR", +// "-D__AVR_ATmega328P__", +// "-D__AVR__", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/tools/avr/lib/gcc/avr/4.8.1/include/", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/variants/eightanaloginputs", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire", +// "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/EEPROM", +// "-I/Users/apla/Documents/Arduino/libraries/Time", +// "-I/Users/apla/Documents/Arduino/libraries/DS3231RTC", +// "-I/Users/apla/Documents/Arduino/libraries/EtherCard", +// "-I/Users/apla/Documents/Arduino/libraries/JeeLib" + ], [], { + incomplete: true, + precompiledPreamble: true + } +); + +//console.log (Cursor); + +//tu.codeCompleteAt (source, 6, 9); +tu.codeCompleteAt (source, 4, 1); + +return; + +tu.cursor.visitChildren(function (parent) { + // console.log (parent); + // if (this.spelling === "analogRead") { + console.log (this.spelling, this.kind, this.location.presumedLocation); + // } + switch (this.kind) { + case Cursor.FunctionDecl: + console.log('function', this.spelling, this.location.presumedLocation); + // TODO: try/catch? + var self = this; + // this.visitChildren (function (parent) { + // console.log ('function', self.spelling, 'has child', this.spelling); + // }); + //console.log('displayName', this.displayName); + // console.log (this); + // process.exit(0); + break; + case Cursor.MacroDefinition: + // console.log('macro', this.spelling); + break; + case Cursor.InclusionDirective: + // console.log('inclusion', this.spelling); + break; + } + return Cursor.Continue; +}); + +index.dispose(); +//tu.dispose(); diff --git a/completion/arduino-test-clang/Arduino.h b/completion/arduino-test-clang/Arduino.h new file mode 100644 index 0000000..ac775f1 --- /dev/null +++ b/completion/arduino-test-clang/Arduino.h @@ -0,0 +1,249 @@ +/* + Arduino.h - Main include file for the Arduino SDK + Copyright (c) 2005-2013 Arduino Team. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef Arduino_h +#define Arduino_h + +#include +#include +#include +#include + +#include +#include +#include + +#include "binary.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +void yield(void); + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#define SERIAL 0x0 +#define DISPLAY 0x1 + +#define LSBFIRST 0 +#define MSBFIRST 1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +#define DEFAULT 0 +#define EXTERNAL 1 +#define INTERNAL 2 +#else +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) +#define INTERNAL1V1 2 +#define INTERNAL2V56 3 +#else +#define INTERNAL 3 +#endif +#define DEFAULT 1 +#define EXTERNAL 0 +#endif + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define interrupts() sei() +#define noInterrupts() cli() + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +// avr-libc defines _NOP() since 1.6.2 +#ifndef _NOP +#define _NOP() do { __asm__ volatile ("nop"); } while (0) +#endif + +typedef unsigned int word; + +#define bit(b) (1UL << (b)) + +typedef uint8_t boolean; +typedef uint8_t byte; + +void init(void); +void initVariant(void); + +int atexit(void (*func)()) __attribute__((weak)); + +void pinMode(uint8_t, uint8_t); +void digitalWrite(uint8_t, uint8_t); +int digitalRead(uint8_t); +int analogRead(uint8_t); +void analogReference(uint8_t mode); +void analogWrite(uint8_t, int); + +unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); + +void attachInterrupt(uint8_t, void (*)(void), int mode); +void detachInterrupt(uint8_t); + +void setup(void); +void loop(void); + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. + +#define analogInPinToBit(P) (P) + +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; + +extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; +// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; +extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; + +// Get the bit location within the hardware port of the given virtual pin. +// This comes from the pins_*.c file for the active board configuration. +// +// These perform slightly better as macros compared to inline functions +// +#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) +#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) +#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) ) +#define analogInPinToBit(P) (P) +#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +#define NOT_A_PIN 0 +#define NOT_A_PORT 0 + +#define NOT_AN_INTERRUPT -1 + +#ifdef ARDUINO_MAIN +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 +#endif + +#define NOT_ON_TIMER 0 +#define TIMER0A 1 +#define TIMER0B 2 +#define TIMER1A 3 +#define TIMER1B 4 +#define TIMER1C 5 +#define TIMER2 6 +#define TIMER2A 7 +#define TIMER2B 8 + +#define TIMER3A 9 +#define TIMER3B 10 +#define TIMER3C 11 +#define TIMER4A 12 +#define TIMER4B 13 +#define TIMER4C 14 +#define TIMER4D 15 +#define TIMER5A 16 +#define TIMER5B 17 +#define TIMER5C 18 + +#ifdef __cplusplus +} // extern "C" +#endif + +#ifdef __cplusplus +#include "WCharacter.h" +#include "WString.h" +#include "HardwareSerial.h" +#include "USBAPI.h" +#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL) +#error "Targets with both UART0 and CDC serial not supported" +#endif + +uint16_t makeWord(uint16_t w); +uint16_t makeWord(byte h, byte l); + +#define word(...) makeWord(__VA_ARGS__) + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L); + +void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0); +void noTone(uint8_t _pin); + +// WMath prototypes +long random(long); +long random(long, long); +void randomSeed(unsigned int); +long map(long, long, long, long, long); + +#endif + +#include "pins_arduino.h" + +#endif diff --git a/completion/arduino-test-clang/test.cpp b/completion/arduino-test-clang/test.cpp new file mode 100644 index 0000000..0125b6f --- /dev/null +++ b/completion/arduino-test-clang/test.cpp @@ -0,0 +1,9 @@ +#include "Arduino.h" + +void setup () { + +} + +void loop () { + +} diff --git a/node/clang-domain.js b/node/clang-domain.js new file mode 100644 index 0000000..e66d85a --- /dev/null +++ b/node/clang-domain.js @@ -0,0 +1,163 @@ +(function () { + "use strict"; + + var os = require("os"); + var fs = require('fs'); + var path = require ('path'); + + var _domainManager; + + var ClangProject = require ('./clang-project.js'); + + var projects = {}; + + // probably best time to init cuwire projects — at brackets project open + // + + /** + * initialize project + * @param {String} projectRoot project root + */ + function initProject (projectRoot) { + // actually we can have multiple arduino/... projects within brackets project, + // so we store each project handle + projects[projectRoot] = { + clang: new ClangProject (projectRoot), + cuwire: null + }; + // 1) get project real dir and build dir + // 2) call cuwire context if we have a mcu project + // 3) call gcc via clang to determine defines (assume we have clang without AVR support) + // 4) prepare project, but compile + } + + function closeProject (projectRoot) { + + } + + /** + * get function names for file + * @param {String} fileName file name to gather function names + */ + function getFunctionNames (fileName) { + // 1) get project instance + // 2) call clang project method + } + + /** + * get a completions list for position in file + * @param {String} fileName path to source file name + * @param {Number} line line number + * @param {Number} column column number + */ + function getCompletionAt (fileName, line, column) { + // 1) get project instance + // 2) call clang project method + } + + function getFunctionLocations (functionName) { + // 1) get project instance + // 2) call clang project method + } + + + var domainName = "clang"; + + /** + * Initializes the domain + * @param {DomainManager} domainManager The DomainManager for the server + */ + function init(domainManager) { + if (!domainManager.hasDomain(domainName)) { + domainManager.registerDomain(domainName, {major: 0, minor: 1}); + } + _domainManager = domainManager; + domainManager.registerCommand( + domainName, // domain name + "initProject", // command name + initProject, // command handler function + true, // this command is asynchronous in Node + "Initialize project", + [], + [{name: "ports", // return values + type: "array", + description: "serial port path names"}] + ); + domainManager.registerCommand( + domainName, // domain name + "getFunctionNames", // command name + getFunctionNames, // command handler function + true, // this command is asynchronous in Node + "get function names", + [{ + name: "port", + type: "string", + description: "port name/path" + }, { + name: "baudrate", + type: "int", + description: "port baudrate" + }], + [] + ); + domainManager.registerCommand( + domainName, // domain name + "getFunctionLocations", // command name + getFunctionLocations, // command handler function + true, // this command is asynchronous in Node + "Close a serial port", + [{ + name: "port", + type: "string", + description: "port name/path" + }], + [] + ); + domainManager.registerCommand( + domainName, // domain name + "getCompletionAt", // command name + getCompletionAt, // command handler function + true, // this command is asynchronous in Node + "Send message to a serial port", + [{ + name: "port", + type: "string", + description: "port name/path" + }, { + name: "message", + type: "string", + description: "message to send to port" + }], + [] + ); + domainManager.registerEvent( + domainName, // domain name + "log", // event name + [{ + name: "scope", + type: "string", + description: "message scope" + }, { + name: "message", + type: "string", + description: "log string" + }, { + name: "payload", + type: "object", + description: "log message payload" + }] + ); + domainManager.registerEvent( + domainName, // domain name + "serialMessage", // event name + [{ + name: "message", + type: "string", + description: "message" + }] + ); + } + + exports.init = init; + +}()); diff --git a/node/clang-project.js b/node/clang-project.js new file mode 100644 index 0000000..1d7fcc5 --- /dev/null +++ b/node/clang-project.js @@ -0,0 +1,164 @@ +var libclang = require('libclang'); + +var Index = libclang.Index, + Cursor = libclang.Cursor, + TU = libclang.TranslationUnit; + + +function ClangProject (argv, options) { + this.clangIndex = new Index(true, true); + + if (options && options.template === 'arduino') { + var arduinoRuntime = options.arduinoRuntime; + this.argv = [].concat ([ + "-Wno-unknown-attributes", + "-Wno-attributes", + //"-fsyntax-only", // ignored when parsing + "-nostdinc", + //"-nostdlibinc", + //"-nobuiltininc", + "-MMD", // does it helps? + "-xc++", + "-DF_CPU=16000000L", // some defines depends on it + // probably not needed, but I'll include anyway + "-DARDUINO=158", + "-DARDUINO_AVR_PRO", + "-DARDUINO_ARCH_AVR", + "-D__AVR_ATmega328P__", + "-D__AVR__", + // stdinc + '-I'+arduinoRuntime+'/hardware/tools/avr/lib/gcc/avr/4.8.1/include/', + '-I'+arduinoRuntime+'/hardware/tools/avr/avr/include/', + // core + '-I'+arduinoRuntime+'/hardware/arduino/avr/cores/arduino/', + // variant + '-I'+arduinoRuntime+'/hardware/arduino/avr/variants/eightanaloginputs/', + ], argv); + } else { + this.argv = argv; + } +} + +ClangProject.prototype.lookPreprocessorDefines = function () { + // TODO: match those defines from -mmcpu + // TODO: parse https://github.com/embecosm/avr-gcc/blob/1fff0f74ab020fbfed8740079d03ac06919a5f44/gcc/config/avr/avr-mcus.def + + // even better way: echo | gcc -dM -E - + // from http://stackoverflow.com/questions/2224334/gcc-dump-preprocessor-defines + + // for a mapping -march => define __AVR_AT***__ + // MORE: https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html + +} + + +ClangProject.prototype.lookPreprocessorIncludes = function () { + //`gcc -print-prog-name=cc1plus` -v + //This command asks gcc which C++ preprocessor it is using, and then asks that preprocessor where it looks for includes. + // + //You will get a reliable answer for your specific setup. + // + //Likewise, for the C preprocessor: + // + //`gcc -print-prog-name=cc1` -v + //http://stackoverflow.com/questions/344317/where-does-gcc-look-for-c-and-c-header-files +} + +ClangProject.prototype.parseFile = function (sourceFile, unsavedFiles) { + + var tu = TU.parse ( + this.clangIndex, + sourceFile, + this.argv, + unsavedFiles || [], { + incomplete: true, + precompiledPreamble: true, + // never use this flag, return incorrect function extent end line + // skipFunctionBodies: true + } + ); + return new SourceFile (sourceFile, tu); +} + +ClangProject.prototype.dispose = function () { + this.clangIndex.dispose(); +} + +function SourceFile (fileName, tu) { + this.fileName = fileName; + this.tu = tu; +} + +SourceFile.prototype.functionNames = function (localOnly) { + var functionNames = {}; + + // TODO: local only + + this.tu.cursor.visitChildren(function (parent) { + switch (this.kind) { + case Cursor.FunctionDecl: + if (!this.isDefinition) + return Cursor.Continue; + if (localOnly && !this.location.isFromMainFile) + return Cursor.Continue; + var functionType = this.type.result.declaration.spelling; + + var args = []; + var i, a; + for (i = 0; i < this.type.argTypes; i++) { + a = this.type.getArg(i); + + //console.error('mapping argument', i); + args.push ([a.spelling, a.declaration.displayname]); + } + + var functionExtent = this.extent; + var start = functionExtent.start.presumedLocation; + var end = functionExtent.end.presumedLocation; + + functionNames[this.spelling] = { + location: this.location.presumedLocation, + return: functionType || 'void', + args: args, + isMainFile: this.location.isFromMainFile, + start: { + line: start.line, + column: start.column + }, + end: { + line: end.line, + column: end.column + } + } + + // console.log ('function', functionNames[this.spelling]); + + // TODO: try/catch? + var self = this; + //this.visitChildren (function (parent) { + //console.log ('function', self.spelling, 'has child', this.spelling); + //}); + //console.log('displayName', this.displayName); + //console.log (this); + //process.exit(0); + break; + case Cursor.MacroDefinition: + //console.log('macro', this.spelling); + break; + case Cursor.InclusionDirective: + //console.log('inclusion', this.spelling); + break; + } + return Cursor.Continue; + }); + + return functionNames; +} + +SourceFile.prototype.completionAt = function (line, colZero) { + var col = colZero + 1; + + this.tu.codeCompleteAt (this.fileName, line, col); +} + +module.exports = ClangProject; diff --git a/node/walk-source.js b/node/walk-source.js new file mode 100644 index 0000000..4b5d7a3 --- /dev/null +++ b/node/walk-source.js @@ -0,0 +1,64 @@ +var ClangProject = require ('./clang-project.js'); + +// DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:clang NODE_PATH=/Users/apla/work/mcu/brackets-cuwire/node/node_modules node walk-source.js | less + +var args = [ + // libraries + "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire", + "-I/Applications/devel/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/EEPROM", + "-I/Users/apla/Documents/Arduino/libraries/Time", + "-I/Users/apla/Documents/Arduino/libraries/DS3231RTC", + "-I/Users/apla/Documents/Arduino/libraries/EtherCard", + "-I/Users/apla/Documents/Arduino/libraries/JeeLib" +]; + +var sourceFileName = "/var/folders/r4/d4l8c_ts4rsdc670pdkbtr0m0000gp/T/Sensor-cuwire-5358ae5d/Sensor.cpp"; + +// TODO: use cuwire +var theProject = new ClangProject (args, { + template: 'arduino', + arduinoRuntime: "/Applications/devel/Arduino.app/Contents/Java" +}); + +console.log (theProject, theProject.prototype); + +var sourceFileAST = theProject.parseFile (sourceFileName); + +sourceFileAST.functionNames (); + +sourceFileAST.completionAt (179, 1); + +//var libclangTU = parse_libclang (); + +//var arduinoSourceFile = "arduino-test-clang/test.cpp"; +// +//var arduinoTestTU = parseArduinoTest (arduinoSourceFile); +// +//findAll (arduinoTestTU); +// +//arduinoTestTU.codeCompleteAt (arduinoSourceFile, 4, 1); + + +//return; + +// index.dispose(); +//tu.dispose(); + + +function parse_libclang () { + var index2 = new Index(true, true); + + var source2 = "/Users/apla/work/mcu/brackets-cuwire/clang+llvm-3.5.0-macosx-apple-darwin/include/clang-c/Index.h"; + + var tu2 = TU.parse ( + index, + source2, [ + '-I/Users/apla/work/mcu/brackets-cuwire/clang+llvm-3.5.0-macosx-apple-darwin/include/' + ], [], { + incomplete: true, + precompiledPreamble: true, + skipFunctionBodies: true + } + ); + return tu2; +}