mirror of
https://github.com/gryf/tagbar.git
synced 2025-12-17 11:30:28 +01:00
Move tests into separate repository
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2,4 +2,3 @@
|
||||
.gitattributes export-ignore
|
||||
README export-ignore
|
||||
.info export-ignore
|
||||
tests/** export-ignore
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
<project name="MyProject" default="dist" basedir=".">
|
||||
<description>
|
||||
simple example build file
|
||||
</description>
|
||||
<!-- set global properties for this build -->
|
||||
<property name="src" location="src"/>
|
||||
<property name="build" location="build"/>
|
||||
<property name="dist" location="dist"/>
|
||||
|
||||
<target name="init">
|
||||
<!-- Create the time stamp -->
|
||||
<tstamp/>
|
||||
<!-- Create the build directory structure used by compile -->
|
||||
<mkdir dir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init"
|
||||
description="compile the source " >
|
||||
<!-- Compile the java code from ${src} into ${build} -->
|
||||
<javac srcdir="${src}" destdir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="dist" depends="compile"
|
||||
description="generate the distribution" >
|
||||
<!-- Create the distribution directory -->
|
||||
<mkdir dir="${dist}/lib"/>
|
||||
|
||||
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
|
||||
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="clean"
|
||||
description="clean up" >
|
||||
<!-- Delete the ${build} and ${dist} directory trees -->
|
||||
<delete dir="${build}"/>
|
||||
<delete dir="${dist}"/>
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,39 +0,0 @@
|
||||
Game Port
|
||||
|
||||
; GAMEPORT.ASM
|
||||
;
|
||||
|
||||
.MODEL TINY
|
||||
|
||||
.DATA
|
||||
|
||||
yes DB 13,10,"Game port is installed.",13,10,"$"
|
||||
no DB 13,10,"Game port is not installed.",13,10,"$"
|
||||
|
||||
.CODE
|
||||
ORG 100h
|
||||
|
||||
start: mov al, 1 ;value to write to port
|
||||
mov dx, 201h ;port number
|
||||
out dx, al ;write to port
|
||||
mov cx, 0F00h ;# of loops
|
||||
|
||||
port_loop:
|
||||
in al, dx ;read from port
|
||||
and al, 0Fh ;if jstick present, then AL should be
|
||||
cmp al, 0Fh ; 0Fh after ANDing with 0Fh.
|
||||
je jstick_exists
|
||||
loop port_loop
|
||||
mov dx, OFFSET no ;gameport not installed
|
||||
jmp SHORT done
|
||||
|
||||
jstick_exists:
|
||||
mov dx, OFFSET yes ;gameport installed
|
||||
|
||||
done: mov ah, 9h
|
||||
int 21h
|
||||
|
||||
mov ax, 4c00h
|
||||
int 21h
|
||||
|
||||
END start
|
||||
@@ -1,164 +0,0 @@
|
||||
Gets a list of Queue servers under Novell Netware 3.11
|
||||
|
||||
%PAGESIZE 55,200
|
||||
%SUBTTL "Get List of Queue Servers under Netware 3.11"
|
||||
; Net_Q.Asm
|
||||
;
|
||||
|
||||
.MODEL SMALL
|
||||
|
||||
|
||||
.STACK 100h
|
||||
|
||||
DOSint macro function
|
||||
mov ah,function
|
||||
int 21h
|
||||
ENDM
|
||||
|
||||
.DATA
|
||||
STDOUT = 1 ; the stdout device handle
|
||||
|
||||
DOS_WRITE_TO_HANDLE = 040h ; Write to File Handle
|
||||
DOS_TERMINATE_EXE = 04Ch ; Terminate Program
|
||||
|
||||
NOVELL_FUNCTION = 0E3h
|
||||
;
|
||||
; Object Types
|
||||
; note that they're all big endian
|
||||
;
|
||||
OT_USER = 0100h
|
||||
OT_USER_GROUP = 0200h
|
||||
OT_PRINT_QUEUE = 0300h ; Print Queue object type
|
||||
OT_FILE_SERVER = 0400h
|
||||
|
||||
|
||||
BragMsg DB 0dh,0ah,"NET_Q.EXE",9,"WWW"
|
||||
DB 9,"Version 1.00",0dh,0ah
|
||||
DB 9,9,"released to the public domain by the author",0dh,0ah,0dh,0ah
|
||||
BragLen = $ - BragMsg
|
||||
|
||||
Crlf DB 0dh,0ah,0
|
||||
|
||||
SCAN_REQ STRUC ; bindery ScanObject request packet structure
|
||||
MyLength DW 55 ; the length of this buffer
|
||||
Function DB 37h ; scan object subfunction number
|
||||
ObjectID DD -1 ; all ones for initial object search
|
||||
ObjectType DW -1 ; wild card -- looks for all objects
|
||||
ObjNameLen DB 1 ; at least one character
|
||||
ObjName DB 47 DUP ('*') ; fill with wildcards to start
|
||||
SCAN_REQ ENDS
|
||||
|
||||
SCAN_REP STRUC ; bindery ScanObject request packet structure
|
||||
MyLength DW 57
|
||||
RObjectID DD 0 ; all ones for initial object search
|
||||
RObjectType DW 0 ; wild card -- looks for all objects
|
||||
RObjName DB 48 DUP (0) ; fill with wildcards to start
|
||||
ObjFlag DB 0
|
||||
ObjSecurty DB 0
|
||||
ObjHasProp DB 0
|
||||
ENDS
|
||||
|
||||
ScanObjReq SCAN_REQ <>
|
||||
ScanObjRep SCAN_REP <>
|
||||
|
||||
.CODE
|
||||
|
||||
;
|
||||
; This is the main part of the code
|
||||
;
|
||||
; Test code gets and prints the name of all print queues from the
|
||||
; logged server -- NO ERROR CHECKING IS DONE, so be careful!
|
||||
;
|
||||
|
||||
Start:
|
||||
mov ax,@data
|
||||
mov ds,ax ; set up the data segment
|
||||
mov dx,OFFSET BragMsg ; prepare to print out brag line(s)
|
||||
mov cx,BragLen
|
||||
mov bx,STDOUT ; print to STDOUT
|
||||
DOSint DOS_WRITE_TO_HANDLE
|
||||
jc Exit ; if carry is set, there was an error
|
||||
|
||||
mov [ScanObjReq.ObjectType],OT_PRINT_QUEUE
|
||||
;
|
||||
; in this case the name is already set up, (a wildcard) but if a
|
||||
; specific name were desired, it would be moved to
|
||||
; ScanObjReq.ObjName, with the appropriate length (not including
|
||||
; optional terminating NULL char set up in ScanObjReq.ObjNameLen.
|
||||
;
|
||||
@@MoreQueues:
|
||||
call BindScan
|
||||
jc Exit
|
||||
|
||||
lea dx,[ScanObjRep.ObjName]
|
||||
call Puts
|
||||
lea dx,[Crlf]
|
||||
call Puts
|
||||
jmp @@MoreQueues
|
||||
|
||||
Exit:
|
||||
DOSint DOS_TERMINATE_EXE ; return with error code preset in AL
|
||||
|
||||
;
|
||||
; BindScan
|
||||
;
|
||||
; scans the bindery for the object name set in the request buffer
|
||||
;
|
||||
BindScan proc
|
||||
push ds si di es dx ax
|
||||
|
||||
lea si,[ScanObjReq] ; point DS:DI to request buffer
|
||||
mov dx,ds
|
||||
mov es,dx
|
||||
lea di,[ScanObjRep] ; point ES:SI to reply buffer
|
||||
DOSint NOVELL_FUNCTION
|
||||
jb @@Exit
|
||||
|
||||
cld ; make sure to count up
|
||||
mov si,OFFSET ScanObjRep.ObjectID
|
||||
mov di,OFFSET ScanObjReq.ObjectID
|
||||
movsw
|
||||
movsw
|
||||
|
||||
clc
|
||||
|
||||
@@Exit:
|
||||
pop ax dx es di si ds
|
||||
ret
|
||||
|
||||
BindScan endp
|
||||
|
||||
; Puts
|
||||
;
|
||||
; prints a NUL terminated string to stdout
|
||||
;
|
||||
; INPUTS: ds:dx points to ASCIIZ string
|
||||
;
|
||||
; OUTPUTS: prints string to stdout
|
||||
;
|
||||
; RETURNS: ax = number of bytes actually printed
|
||||
; carry set on error
|
||||
;
|
||||
; DESTROYED: ax
|
||||
;
|
||||
Puts proc
|
||||
push bx cx di es
|
||||
|
||||
push ds
|
||||
pop es
|
||||
mov cx,0ffffh ; maximum length of string
|
||||
mov di,dx
|
||||
cld
|
||||
mov al,0 ; we're looking for NUL
|
||||
repne scasb
|
||||
dec di
|
||||
mov cx,di
|
||||
sub cx,dx
|
||||
mov bx,STDOUT ; write to this device
|
||||
DOSint DOS_WRITE_TO_HANDLE
|
||||
|
||||
pop es di cx bx
|
||||
ret
|
||||
Puts endp
|
||||
|
||||
END Start
|
||||
@@ -1,14 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<%
|
||||
dim fs,d
|
||||
set fs=Server.CreateObject("Scripting.FileSystemObject")
|
||||
set d=fs.GetDrive("c:")
|
||||
Response.Write("The serialnumber is " & d.SerialNumber)
|
||||
set d=nothing
|
||||
set fs=nothing
|
||||
%>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,11 +0,0 @@
|
||||
# ctime.awk
|
||||
#
|
||||
# awk version of C ctime(3) function
|
||||
|
||||
function ctime(ts, format)
|
||||
{
|
||||
format = "%a %b %d %H:%M:%S %Z %Y"
|
||||
if (ts == 0)
|
||||
ts = systime() # use current time as default
|
||||
return strftime(format, ts)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
SuperStrict
|
||||
|
||||
' Threading tutorial 1:
|
||||
' A basic loading thread
|
||||
|
||||
|
||||
' a threadable function
|
||||
' threadable functions must return an Object and take 1 object as input, they don't need to be used
|
||||
Function loadResources:Object(in:Object)
|
||||
Print "Starting a child thread..."
|
||||
For Local counter:Int = 0 Until 20 ' just a loop to make stuff happen
|
||||
Print "Pretending to load resource " + counter
|
||||
Delay(300) ' just to make this take some time like loading a real resource would
|
||||
Next
|
||||
Print "Child thread complete."
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
'####### Main code starts here
|
||||
|
||||
' Create a thread with loadResources() and Null as it's input object value
|
||||
Local loadingThread:TThread = CreateThread(loadResources, Null)
|
||||
|
||||
Print "Starting the main loop..."
|
||||
While(ThreadRunning(loadingThread)) ' as long as that child thread is still running...
|
||||
Print "Waiting on our resources..."
|
||||
Delay(100) ' we could do whatever we want here...
|
||||
Wend
|
||||
Print "Main loop complete."
|
||||
@@ -1,200 +0,0 @@
|
||||
$ SET SOURCEFORMAT"FREE"
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. ACME99.
|
||||
AUTHOR. Michael Coughlan.
|
||||
*CS431399R-EXAM.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT ORDER-FILE ASSIGN TO "ORDERS.DAT"
|
||||
ORGANIZATION IS LINE SEQUENTIAL.
|
||||
|
||||
SELECT STOCK-FILE ASSIGN TO "STOCK.DAT"
|
||||
ORGANIZATION IS RELATIVE
|
||||
ACCESS MODE IS DYNAMIC
|
||||
RELATIVE KEY IS STOCK-REC-POINTER-WB
|
||||
FILE STATUS IS STOCK-STATUS-WB.
|
||||
|
||||
SELECT MANF-FILE ASSIGN TO "MANF.DAT"
|
||||
ORGANIZATION IS INDEXED
|
||||
ACCESS MODE IS RANDOM
|
||||
RECORD KEY IS MANF-CODE-FC
|
||||
ALTERNATE RECORD KEY IS MANF-NAME-FC
|
||||
WITH DUPLICATES
|
||||
FILE STATUS IS MANF-STATUS-WB.
|
||||
|
||||
|
||||
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD ORDER-FILE.
|
||||
01 ORDER-REC-FA.
|
||||
02 ITEM-DESC-FA PIC X(30).
|
||||
02 MANF-NAME-FA PIC X(30).
|
||||
02 QTY-REQUIRED-FA PIC 9(6).
|
||||
02 COST-OF-ITEMS-FA PIC 9(5)V99.
|
||||
02 POSTAGE-FA PIC 99V99.
|
||||
|
||||
FD STOCK-FILE.
|
||||
01 STOCK-REC-FB.
|
||||
02 STOCK-NUM-FB PIC 9(5).
|
||||
02 MANF-CODE-FB PIC X(4).
|
||||
02 ITEM-DESC-FB PIC X(30).
|
||||
02 QTY-IN-STOCK-FB PIC 9(6).
|
||||
02 REORDER-LEVEL-FB PIC 999.
|
||||
02 REORDER-QTY-FB PIC 9(6).
|
||||
02 ITEM-COST-FB PIC 9(5).
|
||||
02 ITEM-WEIGHT-FB PIC 9(5).
|
||||
02 ON-ORDER-FB PIC X.
|
||||
88 NOT-ON-ORDER VALUE "N".
|
||||
88 ON-ORDER VALUE "Y".
|
||||
|
||||
FD MANF-FILE.
|
||||
01 MANF-REC-FC.
|
||||
02 MANF-CODE-FC PIC X(4).
|
||||
02 MANF-NAME-FC PIC X(30).
|
||||
02 MANF-ADDRESS-FC PIC X(70).
|
||||
|
||||
|
||||
|
||||
|
||||
WORKING-STORAGE SECTION.
|
||||
01 CALL-ITEMS-WA.
|
||||
02 POST-CHARGE-WA PIC 99V99.
|
||||
02 POST-NUM-WA PIC 99.
|
||||
|
||||
01 FILE-DATA-WB.
|
||||
02 STOCK-REC-POINTER-WB PIC 9(5).
|
||||
02 STOCK-STATUS-WB PIC XX.
|
||||
02 MANF-STATUS-WB PIC XX.
|
||||
02 FILLER PIC 9 VALUE 0.
|
||||
88 END-OF-FILE VALUE 1.
|
||||
|
||||
01 UNSTRING-DATA-WC.
|
||||
02 UNSTRING-POINTER-WC PIC 99.
|
||||
88 END-OF-ADDRESS VALUE 71.
|
||||
02 HOLD-STRING-WC PIC X(10).
|
||||
02 COUNTY-WC PIC X(9).
|
||||
88 NORTHERN-COUNTY
|
||||
VALUE "ANTRIM", "ARMAGH", "DERRY", "DOWN",
|
||||
"FERMANAGH", "TYRONE".
|
||||
02 COUNTRY-WC PIC X(10).
|
||||
88 EEC-COUNTRY
|
||||
VALUE "AUSTRIA", "BELGIUM", "DENMARK", "ENGLAND", "FINLAND",
|
||||
"FRANCE", "GERMANY", "GREECE", "IRELAND", "ITALY",
|
||||
"LUXEMBOURG", "PORTUGAL", "SCOTLAND", "SPAIN",
|
||||
"SWEDEN", "WALES".
|
||||
88 IRELAND VALUE "IRELAND".
|
||||
|
||||
02 COUNTRY-FLAGS-WC PIC 9.
|
||||
88 OTHER-EEC VALUE 1.
|
||||
88 REPUBLIC VALUE 0.
|
||||
|
||||
01 POSTAGE-DATA-WD.
|
||||
02 TOTAL-WEIGHT-WD PIC 9(5).
|
||||
88 OVER-WEIGHT VALUE 50001 THRU 99999.
|
||||
|
||||
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
CREATE-REORDER-FILE.
|
||||
OPEN I-O STOCK-FILE.
|
||||
OPEN INPUT MANF-FILE.
|
||||
OPEN OUTPUT ORDER-FILE.
|
||||
READ STOCK-FILE NEXT RECORD
|
||||
AT END SET END-OF-FILE TO TRUE
|
||||
END-READ.
|
||||
PERFORM UNTIL END-OF-FILE
|
||||
IF (QTY-IN-STOCK-FB NOT GREATER THAN REORDER-LEVEL-FB)
|
||||
AND (NOT-ON-ORDER)
|
||||
PERFORM CREATE-REORDER-RECORD
|
||||
PERFORM UPDATE-STOCK-RECORD
|
||||
END-IF
|
||||
READ STOCK-FILE NEXT RECORD
|
||||
AT END SET END-OF-FILE TO TRUE
|
||||
END-READ
|
||||
END-PERFORM.
|
||||
CLOSE STOCK-FILE, MANF-FILE, ORDER-FILE.
|
||||
STOP RUN.
|
||||
|
||||
CREATE-REORDER-RECORD.
|
||||
MOVE MANF-CODE-FB TO MANF-CODE-FC.
|
||||
READ MANF-FILE
|
||||
KEY IS MANF-CODE-FC
|
||||
INVALID KEY DISPLAY "CRR MANF STATUS = "
|
||||
MANF-STATUS-WB "CODE = " MANF-CODE-FC
|
||||
END-READ.
|
||||
PERFORM EXTRACT-ADDRESS-ITEMS.
|
||||
|
||||
MOVE ZEROS TO POSTAGE-FA, COST-OF-ITEMS-FA.
|
||||
IF EEC-COUNTRY
|
||||
PERFORM GET-POSTAGE
|
||||
MULTIPLY ITEM-COST-FB BY REORDER-QTY-FB
|
||||
GIVING COST-OF-ITEMS-FA
|
||||
MOVE POST-CHARGE-WA TO POSTAGE-FA
|
||||
END-IF.
|
||||
|
||||
MOVE ITEM-DESC-FB TO ITEM-DESC-FA.
|
||||
MOVE MANF-NAME-FC TO MANF-NAME-FA.
|
||||
MOVE REORDER-QTY-FB TO QTY-REQUIRED-FA.
|
||||
WRITE ORDER-REC-FA.
|
||||
|
||||
GET-POSTAGE.
|
||||
IF IRELAND AND NOT NORTHERN-COUNTY
|
||||
SET REPUBLIC TO TRUE
|
||||
ELSE
|
||||
SET OTHER-EEC TO TRUE
|
||||
END-IF.
|
||||
MULTIPLY ITEM-WEIGHT-FB BY REORDER-QTY-FB
|
||||
GIVING TOTAL-WEIGHT-WD
|
||||
ON SIZE ERROR MOVE 99999 TO TOTAL-WEIGHT-WD.
|
||||
|
||||
EVALUATE TOTAL-WEIGHT-WD ALSO REPUBLIC ALSO OTHER-EEC
|
||||
WHEN 1 THRU 500 ALSO TRUE ALSO FALSE MOVE 1 TO POST-NUM-WA
|
||||
WHEN 1 THRU 500 ALSO FALSE ALSO TRUE MOVE 2 TO POST-NUM-WA
|
||||
WHEN 501 THRU 1000 ALSO TRUE ALSO FALSE MOVE 3 TO POST-NUM-WA
|
||||
WHEN 501 THRU 1000 ALSO FALSE ALSO TRUE MOVE 4 TO POST-NUM-WA
|
||||
WHEN 1001 THRU 3000 ALSO TRUE ALSO FALSE MOVE 5 TO POST-NUM-WA
|
||||
WHEN 1001 THRU 3000 ALSO FALSE ALSO TRUE MOVE 6 TO POST-NUM-WA
|
||||
WHEN 3001 THRU 5000 ALSO TRUE ALSO FALSE MOVE 7 TO POST-NUM-WA
|
||||
WHEN 3001 THRU 5000 ALSO FALSE ALSO TRUE MOVE 8 TO POST-NUM-WA
|
||||
WHEN 5001 THRU 10000 ALSO TRUE ALSO FALSE MOVE 9 TO POST-NUM-WA
|
||||
WHEN 5001 THRU 10000 ALSO FALSE ALSO TRUE MOVE 10 TO POST-NUM-WA
|
||||
WHEN 10001 THRU 50000 ALSO TRUE ALSO FALSE MOVE 11 TO POST-NUM-WA
|
||||
WHEN 10001 THRU 50000 ALSO FALSE ALSO TRUE MOVE 12 TO POST-NUM-WA
|
||||
WHEN 50001 THRU 99999 ALSO ANY ALSO ANY MOVE ZEROS
|
||||
TO POST-CHARGE-WA
|
||||
WHEN OTHER DISPLAY "EVALUATE WRONG:- WEIGHT = " TOTAL-WEIGHT-WD
|
||||
" COUNTRY FLAG = " COUNTRY-FLAGS-WC
|
||||
END-EVALUATE.
|
||||
IF NOT OVER-WEIGHT
|
||||
CALL "POSTAGE-RATE"
|
||||
USING BY CONTENT POST-NUM-WA
|
||||
BY REFERENCE POST-CHARGE-WA
|
||||
END-IF.
|
||||
|
||||
|
||||
|
||||
UPDATE-STOCK-RECORD.
|
||||
MOVE "Y" TO ON-ORDER-FB.
|
||||
REWRITE STOCK-REC-FB
|
||||
INVALID KEY DISPLAY "STOCK REWRITE STATUS = " STOCK-STATUS-WB
|
||||
END-REWRITE.
|
||||
|
||||
|
||||
|
||||
EXTRACT-ADDRESS-ITEMS.
|
||||
MOVE 1 TO UNSTRING-POINTER-WC.
|
||||
PERFORM UNTIL END-OF-ADDRESS
|
||||
MOVE HOLD-STRING-WC TO COUNTY-WC
|
||||
UNSTRING MANF-ADDRESS-FC DELIMITED BY ","
|
||||
INTO HOLD-STRING-WC
|
||||
WITH POINTER UNSTRING-POINTER-WC
|
||||
END-PERFORM.
|
||||
MOVE HOLD-STRING-WC TO COUNTRY-WC.
|
||||
|
||||
*debugging displays
|
||||
DISPLAY "COUNTY = " COUNTY-WC.
|
||||
DISPLAY "COUNTRY = " COUNTRY-WC.
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
$ SET SOURCEFORMAT"FREE"
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. DriverProg.
|
||||
AUTHOR. Michael Coughlan.
|
||||
* This program demonstrates the use of the CALL verb
|
||||
* it calls three external sub-programs that help to demonstrate
|
||||
* some of the features of the CALL.
|
||||
* The "MultiplyNums" sub-program takes five parameters. The first two
|
||||
* are the numbers to be multiplied, the second two are strings to
|
||||
* demonstrate that strings can be passed as parameters and the
|
||||
* last is the returned result of multiplying the two numbers.
|
||||
* The "Fickle" sub-program demonstrates a program that exhibits
|
||||
* State Memory.
|
||||
* The "Steadfast" sub-program demonstrates how a sub-program that
|
||||
* uses the IS INITIAL phrase can avoid State Memory.
|
||||
|
||||
ENVIRONMENT DIVISION.
|
||||
DATA DIVISION.
|
||||
|
||||
WORKING-STORAGE SECTION.
|
||||
01 UserNumber PIC 99.
|
||||
|
||||
01 PrnResult PIC 9(6).
|
||||
* field declared as COMP cannot be DISPLAYed
|
||||
* it is necessary to move it to a DISPLAY field.
|
||||
* DISPLAY is the default value for a field and
|
||||
* need not be declared.
|
||||
|
||||
|
||||
* Parameters must be either 01-level's or elementry
|
||||
* data-items.
|
||||
01 Parameters.
|
||||
02 Number1 PIC 9(3).
|
||||
02 Number2 PIC 9(3).
|
||||
02 FirstString PIC X(19) VALUE "First parameter = ".
|
||||
02 SecondString PIC X(19) VALUE "Second parameter = ".
|
||||
02 Result PIC 9(6) COMP.
|
||||
* I've made this a COMP field to demonstrate that COMP
|
||||
* items can be passed as parameters but a COMP field cannot
|
||||
* be DISPLAYed and so is moved to a DISPLAY field before DISPLAYing it.
|
||||
|
||||
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
Begin.
|
||||
PERFORM CallMultiplyNums.
|
||||
PERFORM CallFickle
|
||||
PERFORM CallSteadfast
|
||||
|
||||
PERFORM MakeFickleSteadfast.
|
||||
|
||||
STOP RUN.
|
||||
|
||||
|
||||
CallMultiplyNums.
|
||||
DISPLAY "Input 2 numbers (3 digits each) to be multiplied"
|
||||
DISPLAY "First number - " WITH NO ADVANCING
|
||||
ACCEPT Number1
|
||||
DISPLAY "Second number - " WITH NO ADVANCING
|
||||
ACCEPT Number2.
|
||||
DISPLAY "The first string is " FirstString.
|
||||
DISPLAY "The second string is " SecondString.
|
||||
DISPLAY ">>>>>>>>> Calling the sub-program now".
|
||||
|
||||
CALL "MultiplyNums"
|
||||
USING BY CONTENT Number1, Number2, FirstString,
|
||||
BY REFERENCE SecondString, Result.
|
||||
|
||||
* The USING phrase specifies the parameters to be passed to the
|
||||
* sub-program. The order of the parameters is important as the
|
||||
* sub-program recognizes them by relative location not by name
|
||||
*
|
||||
* Parameters should be passed BY CONTENT when you are not expecting
|
||||
* them to get a value from the called program. We have not passed
|
||||
* SecondString by content and you can see that its value is
|
||||
* overwritten by the called program.
|
||||
|
||||
DISPLAY "Back in the main program now <<<<<<<<<<<".
|
||||
MOVE Result to PrnResult.
|
||||
DISPLAY Number1 " multiplied by " Number2 " is = " PrnResult.
|
||||
|
||||
DISPLAY "The first string is " FirstString.
|
||||
DISPLAY "The second string is " SecondString.
|
||||
|
||||
|
||||
CallFickle.
|
||||
DISPLAY SPACE
|
||||
DISPLAY "------------------- Calling Fickle ---------"
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber.
|
||||
* Every time I call Fickle with the same value
|
||||
* produces a different result. This is because
|
||||
* it remembers its state from one call to the next.
|
||||
* It has "State Memory".
|
||||
|
||||
|
||||
CallSteadFast.
|
||||
DISPLAY SPACE
|
||||
DISPLAY "------------------- Calling Steadfast ---------"
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Steadfast" USING BY CONTENT UserNumber
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Steadfast" USING BY CONTENT UserNumber
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Steadfast" USING BY CONTENT UserNumber.
|
||||
* Every time I call Steadfast with the same value
|
||||
* it produces the same result. We have eliminated
|
||||
* State Memory by using the IS INITIAL phrase in
|
||||
* Steadfast
|
||||
|
||||
|
||||
MakeFickleSteadfast.
|
||||
DISPLAY SPACE
|
||||
DISPLAY "----- Making fickle act like Steadfast -------"
|
||||
CANCEL "Fickle"
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber
|
||||
|
||||
CANCEL "Fickle"
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber
|
||||
|
||||
CANCEL "Fickle"
|
||||
MOVE 10 TO UserNumber
|
||||
CALL "Fickle" USING BY CONTENT UserNumber.
|
||||
* We can make Fickle act like Steadfast by using
|
||||
* the CANCEL verb to set it into its initial state
|
||||
* each time we call it
|
||||
@@ -1,251 +0,0 @@
|
||||
Robot = require '../robot'
|
||||
Adapter = require '../adapter'
|
||||
|
||||
HTTPS = require 'https'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
class Campfire extends Adapter
|
||||
|
||||
send: (user, strings...) ->
|
||||
if strings.length > 0
|
||||
@bot.Room(user.room).speak strings.shift(), (err, data) =>
|
||||
@robot.logger.error "Campfire error: #{err}" if err?
|
||||
@send user, strings...
|
||||
|
||||
reply: (user, strings...) ->
|
||||
@send user, strings.map((str) -> "#{user.name}: #{str}")...
|
||||
|
||||
topic: (user, strings...) ->
|
||||
@bot.Room(user.room).topic strings.join(" / "), (err, data) =>
|
||||
@robot.logger.error "Campfire error: #{err}" if err?
|
||||
|
||||
run: ->
|
||||
self = @
|
||||
|
||||
options =
|
||||
token: process.env.HUBOT_CAMPFIRE_TOKEN
|
||||
rooms: process.env.HUBOT_CAMPFIRE_ROOMS
|
||||
account: process.env.HUBOT_CAMPFIRE_ACCOUNT
|
||||
|
||||
bot = new CampfireStreaming(options, @robot)
|
||||
|
||||
withAuthor = (callback) -> (id, created, room, user, body) ->
|
||||
bot.User user, (err, userData) ->
|
||||
if userData.user
|
||||
author = self.userForId(userData.user.id, userData.user)
|
||||
self.robot.brain.data.users[userData.user.id].name = userData.user.name
|
||||
self.robot.brain.data.users[userData.user.id].email_address = userData.user.email_address
|
||||
author.room = room
|
||||
callback id, created, room, user, body, author
|
||||
|
||||
bot.on "TextMessage", withAuthor (id, created, room, user, body, author) ->
|
||||
unless bot.info.id == author.id
|
||||
self.receive new Robot.TextMessage(author, body)
|
||||
|
||||
bot.on "EnterMessage", withAuthor (id, created, room, user, body, author) ->
|
||||
unless bot.info.id == author.id
|
||||
self.receive new Robot.EnterMessage(author)
|
||||
|
||||
bot.on "LeaveMessage", withAuthor (id, created, room, user, body, author) ->
|
||||
unless bot.info.id == author.id
|
||||
self.receive new Robot.LeaveMessage(author)
|
||||
|
||||
bot.Me (err, data) ->
|
||||
bot.info = data.user
|
||||
bot.name = bot.info.name
|
||||
|
||||
for roomId in bot.rooms
|
||||
do (roomId) ->
|
||||
bot.Room(roomId).join (err, callback) ->
|
||||
bot.Room(roomId).listen()
|
||||
|
||||
bot.on "reconnect", (roomId) ->
|
||||
bot.Room(roomId).join (err, callback) ->
|
||||
bot.Room(roomId).listen()
|
||||
|
||||
@bot = bot
|
||||
|
||||
self.emit "connected"
|
||||
|
||||
exports.use = (robot) ->
|
||||
new Campfire robot
|
||||
|
||||
class CampfireStreaming extends EventEmitter
|
||||
constructor: (options, @robot) ->
|
||||
unless options.token? and options.rooms? and options.account?
|
||||
@robot.logger.error "Not enough parameters provided. I Need a token, rooms and account"
|
||||
process.exit(1)
|
||||
|
||||
@token = options.token
|
||||
@rooms = options.rooms.split(",")
|
||||
@account = options.account
|
||||
@domain = @account + ".campfirenow.com"
|
||||
@authorization = "Basic " + new Buffer("#{@token}:x").toString("base64")
|
||||
|
||||
Rooms: (callback) ->
|
||||
@get "/rooms", callback
|
||||
|
||||
User: (id, callback) ->
|
||||
@get "/users/#{id}", callback
|
||||
|
||||
Me: (callback) ->
|
||||
@get "/users/me", callback
|
||||
|
||||
Room: (id) ->
|
||||
self = @
|
||||
logger = @robot.logger
|
||||
|
||||
show: (callback) ->
|
||||
self.post "/room/#{id}", "", callback
|
||||
|
||||
join: (callback) ->
|
||||
self.post "/room/#{id}/join", "", callback
|
||||
|
||||
leave: (callback) ->
|
||||
self.post "/room/#{id}/leave", "", callback
|
||||
|
||||
lock: (callback) ->
|
||||
self.post "/room/#{id}/lock", "", callback
|
||||
|
||||
unlock: (callback) ->
|
||||
self.post "/room/#{id}/unlock", "", callback
|
||||
|
||||
# say things to this channel on behalf of the token user
|
||||
paste: (text, callback) ->
|
||||
@message text, "PasteMessage", callback
|
||||
|
||||
topic: (text, callback) ->
|
||||
body = {room: {topic: text}}
|
||||
self.put "/room/#{id}", body, callback
|
||||
|
||||
sound: (text, callback) ->
|
||||
@message text, "SoundMessage", callback
|
||||
|
||||
speak: (text, callback) ->
|
||||
body = { message: { "body":text } }
|
||||
self.post "/room/#{id}/speak", body, callback
|
||||
|
||||
message: (text, type, callback) ->
|
||||
body = { message: { "body":text, "type":type } }
|
||||
self.post "/room/#{id}/speak", body, callback
|
||||
|
||||
# listen for activity in channels
|
||||
listen: ->
|
||||
headers =
|
||||
"Host" : "streaming.campfirenow.com"
|
||||
"Authorization" : self.authorization
|
||||
|
||||
options =
|
||||
"agent" : false
|
||||
"host" : "streaming.campfirenow.com"
|
||||
"port" : 443
|
||||
"path" : "/room/#{id}/live.json"
|
||||
"method" : "GET"
|
||||
"headers": headers
|
||||
|
||||
request = HTTPS.request options, (response) ->
|
||||
response.setEncoding("utf8")
|
||||
|
||||
buf = ''
|
||||
|
||||
response.on "data", (chunk) ->
|
||||
if chunk is ' '
|
||||
# campfire api sends a ' ' heartbeat every 3s
|
||||
|
||||
else if chunk.match(/^\s*Access Denied/)
|
||||
# errors are not json formatted
|
||||
logger.error "Campfire error on room #{id}: #{chunk}"
|
||||
|
||||
else
|
||||
# api uses newline terminated json payloads
|
||||
# buffer across tcp packets and parse out lines
|
||||
buf += chunk
|
||||
|
||||
while (offset = buf.indexOf("\r")) > -1
|
||||
part = buf.substr(0, offset)
|
||||
buf = buf.substr(offset + 1)
|
||||
|
||||
if part
|
||||
try
|
||||
data = JSON.parse part
|
||||
self.emit data.type, data.id, data.created_at, data.room_id, data.user_id, data.body
|
||||
catch err
|
||||
logger.error "Campfire error: #{err}"
|
||||
|
||||
response.on "end", ->
|
||||
logger.error "Streaming connection closed for room #{id}. :("
|
||||
setTimeout (->
|
||||
self.emit "reconnect", id
|
||||
), 5000
|
||||
|
||||
response.on "error", (err) ->
|
||||
logger.error "Campfire response error: #{err}"
|
||||
|
||||
request.on "error", (err) ->
|
||||
logger.error "Campfire request error: #{err}"
|
||||
|
||||
request.end()
|
||||
|
||||
# Convenience HTTP Methods for posting on behalf of the token"d user
|
||||
get: (path, callback) ->
|
||||
@request "GET", path, null, callback
|
||||
|
||||
post: (path, body, callback) ->
|
||||
@request "POST", path, body, callback
|
||||
|
||||
put: (path, body, callback) ->
|
||||
@request "PUT", path, body, callback
|
||||
|
||||
request: (method, path, body, callback) ->
|
||||
logger = @robot.logger
|
||||
|
||||
headers =
|
||||
"Authorization" : @authorization
|
||||
"Host" : @domain
|
||||
"Content-Type" : "application/json"
|
||||
|
||||
options =
|
||||
"agent" : false
|
||||
"host" : @domain
|
||||
"port" : 443
|
||||
"path" : path
|
||||
"method" : method
|
||||
"headers": headers
|
||||
|
||||
if method is "POST" || method is "PUT"
|
||||
if typeof(body) isnt "string"
|
||||
body = JSON.stringify body
|
||||
|
||||
body = new Buffer(body)
|
||||
options.headers["Content-Length"] = body.length
|
||||
|
||||
request = HTTPS.request options, (response) ->
|
||||
data = ""
|
||||
|
||||
response.on "data", (chunk) ->
|
||||
data += chunk
|
||||
|
||||
response.on "end", ->
|
||||
if response.statusCode >= 400
|
||||
switch response.statusCode
|
||||
when 401
|
||||
throw new Error "Invalid access token provided, campfire refused the authentication"
|
||||
else
|
||||
logger.error "Campfire error: #{response.statusCode}"
|
||||
|
||||
try
|
||||
callback null, JSON.parse(data)
|
||||
catch err
|
||||
callback null, data or { }
|
||||
|
||||
response.on "error", (err) ->
|
||||
logger.error "Campfire response error: #{err}"
|
||||
callback err, { }
|
||||
|
||||
if method is "POST" || method is "PUT"
|
||||
request.end(body, 'binary')
|
||||
else
|
||||
request.end()
|
||||
|
||||
request.on "error", (err) ->
|
||||
logger.error "Campfire request error: #{err}"
|
||||
@@ -1,588 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: sw=4 ts=4 et :
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Jones <jones.chris.g@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef mozilla_DeadlockDetector_h
|
||||
#define mozilla_DeadlockDetector_h
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "plhash.h"
|
||||
#include "prlock.h"
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifdef NS_TRACE_MALLOC
|
||||
# include "nsTraceMalloc.h"
|
||||
#endif // ifdef NS_TRACE_MALLOC
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
// FIXME bug 456272: split this off into a convenience API on top of
|
||||
// nsStackWalk?
|
||||
class NS_COM_GLUE CallStack
|
||||
{
|
||||
private:
|
||||
#ifdef NS_TRACE_MALLOC
|
||||
typedef nsTMStackTraceID callstack_id;
|
||||
// needs to be a macro to avoid disturbing the backtrace
|
||||
# define NS_GET_BACKTRACE() NS_TraceMallocGetStackTrace()
|
||||
#else
|
||||
typedef void* callstack_id;
|
||||
# define NS_GET_BACKTRACE() 0
|
||||
#endif // ifdef NS_TRACE_MALLOC
|
||||
|
||||
callstack_id mCallStack;
|
||||
|
||||
public:
|
||||
/**
|
||||
* CallStack
|
||||
* *ALWAYS* *ALWAYS* *ALWAYS* call this with no arguments. This
|
||||
* constructor takes an argument *ONLY* so that |GET_BACKTRACE()|
|
||||
* can be evaluated in the stack frame of the caller, rather than
|
||||
* that of the constructor.
|
||||
*
|
||||
* *BEWARE*: this means that calling this constructor with no
|
||||
* arguments is not the same as a "default, do-nothing"
|
||||
* constructor: it *will* construct a backtrace. This can cause
|
||||
* unexpected performance issues.
|
||||
*/
|
||||
CallStack(const callstack_id aCallStack = NS_GET_BACKTRACE()) :
|
||||
mCallStack(aCallStack)
|
||||
{
|
||||
}
|
||||
CallStack(const CallStack& aFrom) :
|
||||
mCallStack(aFrom.mCallStack)
|
||||
{
|
||||
}
|
||||
CallStack& operator=(const CallStack& aFrom)
|
||||
{
|
||||
mCallStack = aFrom.mCallStack;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const CallStack& aOther) const
|
||||
{
|
||||
return mCallStack == aOther.mCallStack;
|
||||
}
|
||||
bool operator!=(const CallStack& aOther) const
|
||||
{
|
||||
return mCallStack != aOther.mCallStack;
|
||||
}
|
||||
|
||||
// FIXME bug 456272: if this is split off,
|
||||
// NS_TraceMallocPrintStackTrace should be modified to print into
|
||||
// an nsACString
|
||||
void Print(FILE* f) const
|
||||
{
|
||||
#ifdef NS_TRACE_MALLOC
|
||||
if (this != &kNone && mCallStack) {
|
||||
NS_TraceMallocPrintStackTrace(f, mCallStack);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
fputs(" [stack trace unavailable]\n", f);
|
||||
}
|
||||
|
||||
/** The "null" callstack. */
|
||||
static const CallStack kNone;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* DeadlockDetector
|
||||
*
|
||||
* The following is an approximate description of how the deadlock detector
|
||||
* works.
|
||||
*
|
||||
* The deadlock detector ensures that all blocking resources are
|
||||
* acquired according to a partial order P. One type of blocking
|
||||
* resource is a lock. If a lock l1 is acquired (locked) before l2,
|
||||
* then we say that |l1 <_P l2|. The detector flags an error if two
|
||||
* locks l1 and l2 have an inconsistent ordering in P; that is, if
|
||||
* both |l1 <_P l2| and |l2 <_P l1|. This is a potential error
|
||||
* because a thread acquiring l1,l2 according to the first order might
|
||||
* race with a thread acquiring them according to the second order.
|
||||
* If this happens under the right conditions, then the acquisitions
|
||||
* will deadlock.
|
||||
*
|
||||
* This deadlock detector doesn't know at compile-time what P is. So,
|
||||
* it tries to discover the order at run time. More precisely, it
|
||||
* finds <i>some</i> order P, then tries to find chains of resource
|
||||
* acquisitions that violate P. An example acquisition sequence, and
|
||||
* the orders they impose, is
|
||||
* l1.lock() // current chain: [ l1 ]
|
||||
* // order: { }
|
||||
*
|
||||
* l2.lock() // current chain: [ l1, l2 ]
|
||||
* // order: { l1 <_P l2 }
|
||||
*
|
||||
* l3.lock() // current chain: [ l1, l2, l3 ]
|
||||
* // order: { l1 <_P l2, l2 <_P l3, l1 <_P l3 }
|
||||
* // (note: <_P is transitive, so also |l1 <_P l3|)
|
||||
*
|
||||
* l2.unlock() // current chain: [ l1, l3 ]
|
||||
* // order: { l1 <_P l2, l2 <_P l3, l1 <_P l3 }
|
||||
* // (note: it's OK, but weird, that l2 was unlocked out
|
||||
* // of order. we still have l1 <_P l3).
|
||||
*
|
||||
* l2.lock() // current chain: [ l1, l3, l2 ]
|
||||
* // order: { l1 <_P l2, l2 <_P l3, l1 <_P l3,
|
||||
* l3 <_P l2 (!!!) }
|
||||
* BEEP BEEP! Here the detector will flag a potential error, since
|
||||
* l2 and l3 were used inconsistently (and potentially in ways that
|
||||
* would deadlock).
|
||||
*/
|
||||
template <typename T>
|
||||
class DeadlockDetector
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* ResourceAcquisition
|
||||
* Consists simply of a resource and the calling context from
|
||||
* which it was acquired. We pack this information together so
|
||||
* that it can be returned back to the caller when a potential
|
||||
* deadlock has been found.
|
||||
*/
|
||||
struct ResourceAcquisition
|
||||
{
|
||||
const T* mResource;
|
||||
CallStack mCallContext;
|
||||
|
||||
ResourceAcquisition(
|
||||
const T* aResource,
|
||||
const CallStack aCallContext=CallStack::kNone) :
|
||||
mResource(aResource),
|
||||
mCallContext(aCallContext)
|
||||
{
|
||||
}
|
||||
ResourceAcquisition(const ResourceAcquisition& aFrom) :
|
||||
mResource(aFrom.mResource),
|
||||
mCallContext(aFrom.mCallContext)
|
||||
{
|
||||
}
|
||||
ResourceAcquisition& operator=(const ResourceAcquisition& aFrom)
|
||||
{
|
||||
mResource = aFrom.mResource;
|
||||
mCallContext = aFrom.mCallContext;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
typedef nsTArray<ResourceAcquisition> ResourceAcquisitionArray;
|
||||
|
||||
private:
|
||||
typedef nsTArray<PLHashEntry*> HashEntryArray;
|
||||
typedef typename HashEntryArray::index_type index_type;
|
||||
typedef typename HashEntryArray::size_type size_type;
|
||||
enum {
|
||||
NoIndex = HashEntryArray::NoIndex
|
||||
};
|
||||
|
||||
/**
|
||||
* Value type for the ordering table. Contains the other
|
||||
* resources on which an ordering constraint |key < other|
|
||||
* exists. The catch is that we also store the calling context at
|
||||
* which the other resource was acquired; this improves the
|
||||
* quality of error messages when potential deadlock is detected.
|
||||
*/
|
||||
struct OrderingEntry
|
||||
{
|
||||
OrderingEntry() :
|
||||
mFirstSeen(CallStack::kNone),
|
||||
mOrderedLT() // FIXME bug 456272: set to empirical
|
||||
{ // dep size?
|
||||
}
|
||||
~OrderingEntry()
|
||||
{
|
||||
}
|
||||
|
||||
CallStack mFirstSeen; // first site from which the resource appeared
|
||||
HashEntryArray mOrderedLT; // this <_o Other
|
||||
};
|
||||
|
||||
static void* TableAlloc(void* /*pool*/, PRSize size)
|
||||
{
|
||||
return operator new(size);
|
||||
}
|
||||
static void TableFree(void* /*pool*/, void* item)
|
||||
{
|
||||
operator delete(item);
|
||||
}
|
||||
static PLHashEntry* EntryAlloc(void* /*pool*/, const void* key)
|
||||
{
|
||||
return new PLHashEntry;
|
||||
}
|
||||
static void EntryFree(void* /*pool*/, PLHashEntry* entry, PRUintn flag)
|
||||
{
|
||||
delete static_cast<T*>(const_cast<void*>(entry->key));
|
||||
delete static_cast<OrderingEntry*>(entry->value);
|
||||
entry->value = 0;
|
||||
if (HT_FREE_ENTRY == flag)
|
||||
delete entry;
|
||||
}
|
||||
static PLHashNumber HashKey(const void* aKey)
|
||||
{
|
||||
return NS_PTR_TO_INT32(aKey) >> 2;
|
||||
}
|
||||
static const PLHashAllocOps kAllocOps;
|
||||
|
||||
// Hash table "interface" the rest of the code should use
|
||||
|
||||
PLHashEntry** GetEntry(const T* aKey)
|
||||
{
|
||||
return PL_HashTableRawLookup(mOrdering, HashKey(aKey), aKey);
|
||||
}
|
||||
|
||||
void PutEntry(T* aKey)
|
||||
{
|
||||
PL_HashTableAdd(mOrdering, aKey, new OrderingEntry());
|
||||
}
|
||||
|
||||
// XXX need these helper methods because OrderingEntry doesn't have
|
||||
// XXX access to underlying PLHashEntry
|
||||
|
||||
/**
|
||||
* Add the order |aFirst <_o aSecond|.
|
||||
*
|
||||
* WARNING: this does not check whether it's sane to add this
|
||||
* order. In the "best" bad case, when this order already exists,
|
||||
* adding it anyway may unnecessarily result in O(n^2) space. In
|
||||
* the "worst" bad case, adding it anyway will cause
|
||||
* |InTransitiveClosure()| to diverge.
|
||||
*/
|
||||
void AddOrder(PLHashEntry* aLT, PLHashEntry* aGT)
|
||||
{
|
||||
static_cast<OrderingEntry*>(aLT->value)->mOrderedLT
|
||||
.InsertElementSorted(aGT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff the order |aFirst < aSecond| has been
|
||||
* *explicitly* added.
|
||||
*
|
||||
* Does not consider transitivity.
|
||||
*/
|
||||
bool IsOrdered(const PLHashEntry* aFirst, const PLHashEntry* aSecond)
|
||||
const
|
||||
{
|
||||
return NoIndex !=
|
||||
static_cast<const OrderingEntry*>(aFirst->value)->mOrderedLT
|
||||
.BinaryIndexOf(aSecond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the array of all elements "that" for
|
||||
* which the order |this < that| has been explicitly added.
|
||||
*
|
||||
* NOTE: this does *not* consider transitive orderings.
|
||||
*/
|
||||
PLHashEntry* const* GetOrders(const PLHashEntry* aEntry) const
|
||||
{
|
||||
return static_cast<const OrderingEntry*>(aEntry->value)->mOrderedLT
|
||||
.Elements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements "that" for which the order
|
||||
* |this < that| has been explicitly added.
|
||||
*
|
||||
* NOTE: this does *not* consider transitive orderings.
|
||||
*/
|
||||
size_type NumOrders(const PLHashEntry* aEntry) const
|
||||
{
|
||||
return static_cast<const OrderingEntry*>(aEntry->value)->mOrderedLT
|
||||
.Length();
|
||||
}
|
||||
|
||||
/** Make a ResourceAcquisition out of |aEntry|. */
|
||||
ResourceAcquisition MakeResourceAcquisition(const PLHashEntry* aEntry)
|
||||
const
|
||||
{
|
||||
return ResourceAcquisition(
|
||||
static_cast<const T*>(aEntry->key),
|
||||
static_cast<const OrderingEntry*>(aEntry->value)->mFirstSeen);
|
||||
}
|
||||
|
||||
// Throwaway RAII lock to make the following code safer.
|
||||
struct PRAutoLock
|
||||
{
|
||||
PRAutoLock(PRLock* aLock) : mLock(aLock) { PR_Lock(mLock); }
|
||||
~PRAutoLock() { PR_Unlock(mLock); }
|
||||
PRLock* mLock;
|
||||
};
|
||||
|
||||
public:
|
||||
static const PRUint32 kDefaultNumBuckets;
|
||||
|
||||
/**
|
||||
* DeadlockDetector
|
||||
* Create a new deadlock detector.
|
||||
*
|
||||
* @param aNumResourcesGuess Guess at approximate number of resources
|
||||
* that will be checked.
|
||||
*/
|
||||
DeadlockDetector(PRUint32 aNumResourcesGuess = kDefaultNumBuckets)
|
||||
{
|
||||
mOrdering = PL_NewHashTable(aNumResourcesGuess,
|
||||
HashKey,
|
||||
PL_CompareValues, PL_CompareValues,
|
||||
&kAllocOps, 0);
|
||||
if (!mOrdering)
|
||||
NS_RUNTIMEABORT("couldn't initialize resource ordering table");
|
||||
|
||||
mLock = PR_NewLock();
|
||||
if (!mLock)
|
||||
NS_RUNTIMEABORT("couldn't allocate deadlock detector lock");
|
||||
}
|
||||
|
||||
/**
|
||||
* ~DeadlockDetector
|
||||
*
|
||||
* *NOT* thread safe.
|
||||
*/
|
||||
~DeadlockDetector()
|
||||
{
|
||||
PL_HashTableDestroy(mOrdering);
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add
|
||||
* Make the deadlock detector aware of |aResource|.
|
||||
*
|
||||
* WARNING: The deadlock detector owns |aResource|.
|
||||
*
|
||||
* Thread safe.
|
||||
*
|
||||
* @param aResource Resource to make deadlock detector aware of.
|
||||
*/
|
||||
void Add(T* aResource)
|
||||
{
|
||||
PRAutoLock _(mLock);
|
||||
PutEntry(aResource);
|
||||
}
|
||||
|
||||
// Nb: implementing a Remove() method makes the detector "more
|
||||
// unsound." By removing a resource from the orderings, deadlocks
|
||||
// may be missed that would otherwise have been found. However,
|
||||
// removing resources possibly reduces the # of false positives,
|
||||
// and additionally saves space. So it's a trade off; we have
|
||||
// chosen to err on the side of caution and not implement Remove().
|
||||
|
||||
/**
|
||||
* CheckAcquisition This method is called after acquiring |aLast|,
|
||||
* but before trying to acquire |aProposed| from |aCallContext|.
|
||||
* It determines whether actually trying to acquire |aProposed|
|
||||
* will create problems. It is OK if |aLast| is NULL; this is
|
||||
* interpreted as |aProposed| being the thread's first acquisition
|
||||
* of its current chain.
|
||||
*
|
||||
* Iff acquiring |aProposed| may lead to deadlock for some thread
|
||||
* interleaving (including the current one!), the cyclical
|
||||
* dependency from which this was deduced is returned. Otherwise,
|
||||
* 0 is returned.
|
||||
*
|
||||
* If a potential deadlock is detected and a resource cycle is
|
||||
* returned, it is the *caller's* responsibility to free it.
|
||||
*
|
||||
* Thread safe.
|
||||
*
|
||||
* @param aLast Last resource acquired by calling thread (or 0).
|
||||
* @param aProposed Resource calling thread proposes to acquire.
|
||||
* @param aCallContext Calling context whence acquisiton request came.
|
||||
*/
|
||||
ResourceAcquisitionArray* CheckAcquisition(const T* aLast,
|
||||
const T* aProposed,
|
||||
const CallStack& aCallContext)
|
||||
{
|
||||
NS_ASSERTION(aProposed, "null resource");
|
||||
PRAutoLock _(mLock);
|
||||
|
||||
PLHashEntry* second = *GetEntry(aProposed);
|
||||
OrderingEntry* e = static_cast<OrderingEntry*>(second->value);
|
||||
if (CallStack::kNone == e->mFirstSeen)
|
||||
e->mFirstSeen = aCallContext;
|
||||
|
||||
if (!aLast)
|
||||
// don't check if |0 < proposed|; just vamoose
|
||||
return 0;
|
||||
|
||||
PLHashEntry* first = *GetEntry(aLast);
|
||||
|
||||
// this is the crux of the deadlock detector algorithm
|
||||
|
||||
if (first == second) {
|
||||
// reflexive deadlock. fastpath b/c InTransitiveClosure is
|
||||
// not applicable here.
|
||||
ResourceAcquisitionArray* cycle = new ResourceAcquisitionArray();
|
||||
if (!cycle)
|
||||
NS_RUNTIMEABORT("can't allocate dep. cycle array");
|
||||
cycle->AppendElement(MakeResourceAcquisition(first));
|
||||
cycle->AppendElement(ResourceAcquisition(aProposed,
|
||||
aCallContext));
|
||||
return cycle;
|
||||
}
|
||||
if (InTransitiveClosure(first, second)) {
|
||||
// we've already established |last < proposed|. all is well.
|
||||
return 0;
|
||||
}
|
||||
if (InTransitiveClosure(second, first)) {
|
||||
// the order |proposed < last| has been deduced, perhaps
|
||||
// transitively. we're attempting to violate that
|
||||
// constraint by acquiring resources in the order
|
||||
// |last < proposed|, and thus we may deadlock under the
|
||||
// right conditions.
|
||||
ResourceAcquisitionArray* cycle = GetDeductionChain(second, first);
|
||||
// show how acquiring |proposed| would complete the cycle
|
||||
cycle->AppendElement(ResourceAcquisition(aProposed,
|
||||
aCallContext));
|
||||
return cycle;
|
||||
}
|
||||
// |last|, |proposed| are unordered according to our
|
||||
// poset. this is fine, but we now need to add this
|
||||
// ordering constraint.
|
||||
AddOrder(first, second);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff |aTarget| is in the transitive closure of |aStart|
|
||||
* over the ordering relation `<_this'.
|
||||
*
|
||||
* @precondition |aStart != aTarget|
|
||||
*/
|
||||
bool InTransitiveClosure(const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget) const
|
||||
{
|
||||
if (IsOrdered(aStart, aTarget))
|
||||
return true;
|
||||
|
||||
index_type i = 0;
|
||||
size_type len = NumOrders(aStart);
|
||||
for (const PLHashEntry* const* it = GetOrders(aStart);
|
||||
i < len; ++i, ++it)
|
||||
if (InTransitiveClosure(*it, aTarget))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of all resource acquisitions
|
||||
* aStart <_this r1 <_this r2 <_ ... <_ aTarget
|
||||
* from which |aStart <_this aTarget| was deduced, including
|
||||
* |aStart| and |aTarget|.
|
||||
*
|
||||
* Nb: there may be multiple deductions of |aStart <_this
|
||||
* aTarget|. This function returns the first ordering found by
|
||||
* depth-first search.
|
||||
*
|
||||
* Nb: |InTransitiveClosure| could be replaced by this function.
|
||||
* However, this one is more expensive because we record the DFS
|
||||
* search stack on the heap whereas the other doesn't.
|
||||
*
|
||||
* @precondition |aStart != aTarget|
|
||||
*/
|
||||
ResourceAcquisitionArray* GetDeductionChain(
|
||||
const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget)
|
||||
{
|
||||
ResourceAcquisitionArray* chain = new ResourceAcquisitionArray();
|
||||
if (!chain)
|
||||
NS_RUNTIMEABORT("can't allocate dep. cycle array");
|
||||
chain->AppendElement(MakeResourceAcquisition(aStart));
|
||||
|
||||
NS_ASSERTION(GetDeductionChain_Helper(aStart, aTarget, chain),
|
||||
"GetDeductionChain called when there's no deadlock");
|
||||
return chain;
|
||||
}
|
||||
|
||||
// precondition: |aStart != aTarget|
|
||||
// invariant: |aStart| is the last element in |aChain|
|
||||
bool GetDeductionChain_Helper(const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget,
|
||||
ResourceAcquisitionArray* aChain)
|
||||
{
|
||||
if (IsOrdered(aStart, aTarget)) {
|
||||
aChain->AppendElement(MakeResourceAcquisition(aTarget));
|
||||
return true;
|
||||
}
|
||||
|
||||
index_type i = 0;
|
||||
size_type len = NumOrders(aStart);
|
||||
for (const PLHashEntry* const* it = GetOrders(aStart);
|
||||
i < len; ++i, ++it) {
|
||||
aChain->AppendElement(MakeResourceAcquisition(*it));
|
||||
if (GetDeductionChain_Helper(*it, aTarget, aChain))
|
||||
return true;
|
||||
aChain->RemoveElementAt(aChain->Length() - 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The partial order on resource acquisitions used by the deadlock
|
||||
* detector.
|
||||
*/
|
||||
PLHashTable* mOrdering; // T* -> PLHashEntry<OrderingEntry>
|
||||
|
||||
/**
|
||||
* Protects contentious methods.
|
||||
* Nb: can't use mozilla::Mutex since we are used as its deadlock
|
||||
* detector.
|
||||
*/
|
||||
PRLock* mLock;
|
||||
|
||||
DeadlockDetector(const DeadlockDetector& aDD);
|
||||
DeadlockDetector& operator=(const DeadlockDetector& aDD);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
const PLHashAllocOps DeadlockDetector<T>::kAllocOps = {
|
||||
DeadlockDetector<T>::TableAlloc, DeadlockDetector<T>::TableFree,
|
||||
DeadlockDetector<T>::EntryAlloc, DeadlockDetector<T>::EntryFree
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
// FIXME bug 456272: tune based on average workload
|
||||
const PRUint32 DeadlockDetector<T>::kDefaultNumBuckets = 64;
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ifndef mozilla_DeadlockDetector_h
|
||||
@@ -1,597 +0,0 @@
|
||||
/* Test file for C++ language.
|
||||
* Attempt to include as many aspects of the C++ language as possible.
|
||||
* Do not include things tested in test.c since that shares the
|
||||
* same language.
|
||||
*
|
||||
* $Id: test.cpp,v 1.22 2008/05/17 20:12:55 zappo Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/* An include test */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "c++-test.hh"
|
||||
|
||||
#include <c++-test.hh>
|
||||
|
||||
double var1 = 1.2;
|
||||
|
||||
int simple1(int a) {
|
||||
|
||||
}
|
||||
|
||||
struct foo1 {
|
||||
int test;
|
||||
};
|
||||
|
||||
struct foo2 : public foo1 {
|
||||
const int foo21(int a, int b);
|
||||
const int foo22(int a, int b) { return 1 }
|
||||
};
|
||||
|
||||
/* Classes */
|
||||
class class1 {
|
||||
private:
|
||||
int var11;
|
||||
struct foo1 var12;
|
||||
public:
|
||||
int p_var11;
|
||||
struct foo p_var12;
|
||||
};
|
||||
|
||||
class i_class1 : public class1 {
|
||||
private:
|
||||
int var11;
|
||||
struct foo var12;
|
||||
public:
|
||||
int p_var11;
|
||||
struct foo p_var12;
|
||||
};
|
||||
|
||||
class class2 {
|
||||
private:
|
||||
int var21;
|
||||
struct foo var22;
|
||||
public:
|
||||
int p_var21;
|
||||
struct foo p_var22;
|
||||
};
|
||||
|
||||
class i_class2 : public class1, public class2 {
|
||||
private:
|
||||
int var21;
|
||||
struct foo var22;
|
||||
protected:
|
||||
int pt_var21;
|
||||
public:
|
||||
int p_var21;
|
||||
struct foo p_var22;
|
||||
};
|
||||
|
||||
class class3 {
|
||||
/* A class with strange things in it */
|
||||
public:
|
||||
class3(); /* A constructor */
|
||||
enum embedded_foo_enum {
|
||||
a, b, c
|
||||
} embed1;
|
||||
struct embedded_bar_struct {
|
||||
int a;
|
||||
int b;
|
||||
} embed2;
|
||||
class embedded_baz_class {
|
||||
embedded_baz_class();
|
||||
~embedded_baz_class();
|
||||
} embed3;
|
||||
~class3(); /* destructor */
|
||||
|
||||
/* Methods */
|
||||
int method_for_class3(int a, char b);
|
||||
|
||||
int inline_method(int c) { return c; }
|
||||
|
||||
/* Operators */
|
||||
class3& operator^= (const class3& something);
|
||||
|
||||
/* Funny declmods */
|
||||
const class3 * const method_const_ptr_ptr(const int * const argconst) const = 0;
|
||||
};
|
||||
|
||||
class3::class3()
|
||||
{
|
||||
/* Constructor outside the definition. */
|
||||
}
|
||||
|
||||
int class3::method_for_class3(int a, char b)
|
||||
{
|
||||
}
|
||||
|
||||
int class3::method1_for_class3( int a, int &b)
|
||||
{
|
||||
int cvariablename;
|
||||
class3 fooy[];
|
||||
class3 moose = new class3;
|
||||
|
||||
// Complktion testing line should find external members.
|
||||
a = fooy[1].me ;
|
||||
b = cv ;
|
||||
|
||||
if (fooy.emb) {
|
||||
simple1(c);
|
||||
}
|
||||
|
||||
cos(10);
|
||||
abs(10);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char class3::method2_for_class3( int a, int b) throw ( exception1 )
|
||||
{
|
||||
return 'a';
|
||||
}
|
||||
|
||||
void *class3::method3_for_class3( int a, int b) throw ( exception1, exception2 )
|
||||
{
|
||||
int q = a;
|
||||
return "Moose";
|
||||
}
|
||||
|
||||
void *class3::method31_for_class3( int a, int b) throw ( )
|
||||
{
|
||||
int q = a;
|
||||
return "Moose";
|
||||
}
|
||||
|
||||
void *class3::method4_for_class3( int a, int b) reentrant
|
||||
{
|
||||
class3 ct;
|
||||
|
||||
ct.method5_for_class3(1,a);
|
||||
|
||||
pritf();
|
||||
}
|
||||
|
||||
/*
|
||||
* A method on class3.
|
||||
*/
|
||||
void *class3::method5_for_class3( int a, int b) const
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Namespace parsing tests
|
||||
*/
|
||||
namespace NS {
|
||||
class class_in_namespace {
|
||||
int equiv(const NS::class_in_namespace *) const;
|
||||
};
|
||||
}
|
||||
|
||||
int NS::class_in_namespace::equiv(const NS::class_in_namespace *cin) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stuff Klaus found.
|
||||
// Inheritance w/out a specifying for public.
|
||||
class class4 : class1 {
|
||||
// Pure virtual methods.
|
||||
void virtual print () const = 0;
|
||||
|
||||
public:
|
||||
// The whacky constructor type
|
||||
class4()
|
||||
try : class1(args)
|
||||
{
|
||||
// constructor body
|
||||
}
|
||||
catch ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class class5 : public virtual class4 {
|
||||
// Virtual inheritance
|
||||
};
|
||||
|
||||
class class6 : class1 {
|
||||
// Mutable
|
||||
mutable int i;
|
||||
};
|
||||
|
||||
/* Namespaces */
|
||||
namespace namespace1 {
|
||||
void ns_method1() { }
|
||||
|
||||
class n_class1 {
|
||||
public:
|
||||
void method11(int a) { }
|
||||
};
|
||||
|
||||
/* This shouldn't parse due to missing semicolon. */
|
||||
class _n_class2 : public n_class1 {
|
||||
void n_c2_method1(int a, int b) { }
|
||||
};
|
||||
|
||||
// Macros in the namespace
|
||||
#define NSMACRO 1
|
||||
|
||||
// Template in the namespace
|
||||
template<class T> T nsti1(const Foo& foo);
|
||||
template<> int nsti1<int>(const Foo& foo);
|
||||
|
||||
}
|
||||
|
||||
namespace namespace2 {
|
||||
|
||||
using namespace1::n_class1;
|
||||
|
||||
}
|
||||
|
||||
/* Initializers */
|
||||
void tinitializers1(): inita1(False),
|
||||
inita2(False)
|
||||
{
|
||||
inita1= 1;
|
||||
}
|
||||
|
||||
/* How about Extern C type things. */
|
||||
int funny_prototype(int ,int b,float c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int extern_c_1(int a, int b)
|
||||
{
|
||||
|
||||
funny_prototype(1,2,3.4);
|
||||
|
||||
printf("Moose", );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int extern_c_2(int a, int b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Some operator stuff
|
||||
class Action
|
||||
{
|
||||
// Problems!! operator() and operator[] can not be parsed with semantic
|
||||
// 1.4.2 but with latest c.by
|
||||
virtual void operator()(int i, char *p ) = 0;
|
||||
virtual String& operator[]() = 0;
|
||||
virtual void operator!() = 0;
|
||||
virtual void operator->() = 0;
|
||||
virtual T& operator+=();
|
||||
virtual T& operator*();
|
||||
virtual T& operator*=();
|
||||
};
|
||||
|
||||
// class with namespace qualified parents
|
||||
class Multiinherit : public virtual POA::Parent,
|
||||
public virtual POA::Parent1,
|
||||
Parent
|
||||
{
|
||||
private:
|
||||
int i;
|
||||
|
||||
public:
|
||||
Multiinherit();
|
||||
~Multiinherit();
|
||||
|
||||
// method with a list of qualified exceptions
|
||||
void* throwtest()
|
||||
throw(Exception0,
|
||||
Testnamespace::Exception1,
|
||||
Testnamespace::Excpetion2,
|
||||
Testnamespace::testnamespace1::Exception3);
|
||||
|
||||
};
|
||||
|
||||
void*
|
||||
Multiinherit::throwtest()
|
||||
throw (Exception0,
|
||||
Testnamespace::Exception1,
|
||||
Testnamespace::Excpetion2,
|
||||
Testnamespace::testnamespace1::Exception3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Jens Rock <jens.rock@asamnet.de>: Nested classes or structs defined
|
||||
// outside of the containing class/struct.
|
||||
class container
|
||||
{
|
||||
public:
|
||||
struct contained;
|
||||
container();
|
||||
~container();
|
||||
};
|
||||
|
||||
struct container::contained
|
||||
{
|
||||
public:
|
||||
contained();
|
||||
~contained();
|
||||
};
|
||||
|
||||
/*
|
||||
* Ok, how about some template stuff.
|
||||
*/
|
||||
template <class CT, class container = vector<CT> >
|
||||
const CT& max (const CT& a, const CT& b)
|
||||
{
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
// Arne Schmitz found this one
|
||||
std::vector<int> &a, &b, &c;
|
||||
|
||||
class TemplateUsingClass
|
||||
{
|
||||
typedef TestClassMap::iterator iterator;
|
||||
typedef map<long, long> TestClassMap;
|
||||
|
||||
// typedefs with const and volatile
|
||||
typedef const map<long, long> const_TestClassMap;
|
||||
typedef TestClassMap<string>::iterator volatile volatile_iterator;
|
||||
|
||||
map<int, int> mapclassvarthingy;
|
||||
};
|
||||
|
||||
template<class T> T ti1(const Foo& foo);
|
||||
template<> int ti1<int>(const Foo& foo);
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
// Now some namespace and related stuff
|
||||
// -----------------------------------
|
||||
|
||||
using CORBA::LEX::get_token;
|
||||
using Namespace1;
|
||||
|
||||
using namespace POA::std;
|
||||
using namespace Test;
|
||||
|
||||
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Lexer::get_test;
|
||||
string str = "";
|
||||
}
|
||||
|
||||
namespace XXX
|
||||
{
|
||||
|
||||
class Foobar : public virtual POA::Parent,
|
||||
public virtual POA::Parent1,
|
||||
private POA::list<fact>,
|
||||
private map<string>
|
||||
{
|
||||
int i;
|
||||
list <shared_ptr<item> >::const_iterator l;
|
||||
public:
|
||||
|
||||
Foobar();
|
||||
~Foobar();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void test_function(int i);
|
||||
|
||||
};
|
||||
|
||||
// unnamed namespaces - even nested
|
||||
namespace
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Lexer::get_test;
|
||||
string str = "";
|
||||
class FooClass
|
||||
{
|
||||
FooClass();
|
||||
};
|
||||
}
|
||||
|
||||
// some builtin types
|
||||
long long ll = 0;
|
||||
long double d = 0.0;
|
||||
unsigned test;
|
||||
unsigned long int **uli = 0;
|
||||
signed si = 0;
|
||||
signed short ss = 0;
|
||||
short int i = 0;
|
||||
long int li = 0;
|
||||
|
||||
// expressions with namespace/class-qualifyiers
|
||||
ORB_var cGlobalOrb = ORB::_nil();
|
||||
ORB_var1 cGlobalOrb1 = ORB::_test;
|
||||
|
||||
class Testclass
|
||||
{
|
||||
#define TEST 0
|
||||
ini i;
|
||||
|
||||
public:
|
||||
|
||||
Testclass();
|
||||
~Testclass();
|
||||
};
|
||||
|
||||
static void test_function(unsigned int i);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// outside method implementations which should be grouped to type Test
|
||||
XXX&
|
||||
Test::waiting()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Test::print()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// outside method implementations with namespaces which should be grouped to
|
||||
// their complete (incl. namespace) types
|
||||
void*
|
||||
Parser::XXX::Foobar::wait(int i, const char const * const * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void*
|
||||
Namespace1::Test::wait1(int i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
Namespace1::Test::waiting(int i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// a class with some outside implementations which should all be grouped to
|
||||
// this class declaration
|
||||
class ClassWithExternals
|
||||
{
|
||||
private:
|
||||
int i;
|
||||
|
||||
public:
|
||||
ClassWithExternals();
|
||||
~ClassWithExternals();
|
||||
void non_nil();
|
||||
};
|
||||
|
||||
|
||||
// Foobar is not displayed; seems that semantic tries to add this to the class
|
||||
// Foobar but can not find/display it, because contained in the namespace above.
|
||||
void
|
||||
Foobar::non_nil()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// are correctly grouped to the ClassWithExternals class
|
||||
void
|
||||
ClassWithExternals::non_nil()
|
||||
{
|
||||
String s = "lödfjg dlfgkdlfkgjdl";
|
||||
return;
|
||||
}
|
||||
|
||||
ClassWithExternals::ClassWithExternals()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
ClassWithExternals::~ClassWithExternals()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
// Now some macro and define stuff
|
||||
// -------------------------------
|
||||
|
||||
#define TEST 0
|
||||
#define TEST1 "String"
|
||||
|
||||
// The first backslash makes this macro unmatched syntax with semantic 1.4.2!
|
||||
// With flexing \+newline as nothing all is working fine!
|
||||
#define MZK_ENTER(METHOD) \
|
||||
{ \
|
||||
CzkMethodLog lMethodLog(METHOD,"Framework");\
|
||||
}
|
||||
|
||||
#define ZK_ASSERTM(METHOD,ASSERTION,MESSAGE) \
|
||||
{ if(!(ASSERTION))\
|
||||
{\
|
||||
std::ostringstream lMesgStream; \
|
||||
lMesgStream << "Assertion failed: " \
|
||||
<< MESSAGE; \
|
||||
CzkLogManager::doLog(CzkLogManager::FATAL,"",METHOD, \
|
||||
"Assert",lMesgStream); \
|
||||
assert(ASSERTION);\
|
||||
}\
|
||||
}
|
||||
|
||||
// Test if not newline-backslashes are handled correctly
|
||||
string s = "My \"quoted\" string";
|
||||
|
||||
// parsed fine as macro
|
||||
#define FOO (arg) method(arg, "foo");
|
||||
|
||||
// With semantic 1.4.2 this parsed as macro BAR *and* function method.
|
||||
// With latest c.bnf at least one-liner macros can be parsed correctly.
|
||||
#define BAR (arg) CzkMessageLog method(arg, "bar");
|
||||
|
||||
// some const and volatile stuff
|
||||
char * p1 = "Hello"; // 1. variable Pointer, variable Data
|
||||
const char * p2 = "Hello"; // 2. variable pointer, constant data
|
||||
char * const p3 = "Hello"; // 3. constant pointer, variable data
|
||||
const char * const p4 = "Hello"; // 4. constant pointer, constant data
|
||||
|
||||
// Case 2 and 4 can exchange first "const" and "char"
|
||||
char const * p21 = "Hello"; // variable pointer, constant data
|
||||
char const * const p41 = "Hello"; // constant pointer, constant data
|
||||
|
||||
char volatile a = 0; // a volatile char
|
||||
void foo(bar const &arg); // a reference to a const bar
|
||||
int foobar(bar const * const p); // a const pointer to a const bar
|
||||
int foobar(bar const volatile * const p); // a const pointer to a const bar
|
||||
int foobar3(char* p); // a const pointer to a const bar
|
||||
|
||||
// Should not be parsed because this is invalid code
|
||||
int const & const r3 = i;
|
||||
|
||||
boolean i = 0;
|
||||
boolean & r1 = i;
|
||||
boolean const & r2 = i;
|
||||
|
||||
// const * sequences can be very long in C++ ;-)
|
||||
char const * const * const * const * ppp;
|
||||
|
||||
// complex function declarationen with named pointer-arguments
|
||||
const char** foobar1(volatile char const * const **p);
|
||||
const char** foobar11(volatile Test::Namespace::Char<char*> const * const **p);
|
||||
|
||||
// complex function declarationen with unnamed pointer-arguments
|
||||
const char* foobar2(const char***);
|
||||
const char* foobar21(const Test::Namespace::Char<char>***);
|
||||
|
||||
// string literal parsing even with wchar_t
|
||||
char const *p = "string1";
|
||||
char const *q = "string1" "str\"ing2" "string3";
|
||||
wchar_t testc = L'a';
|
||||
|
||||
wchar_t const *wp = L"string with a \" in it";
|
||||
wchar_t const *wq = L"string \n\t\"test" L"string2";
|
||||
wchar_t const *wr = L"string L";
|
||||
@@ -1,8 +0,0 @@
|
||||
#include <pd/http/client.H>
|
||||
|
||||
namespace phantom { namespace io_stream { namespace proto_http {
|
||||
namespace handler_bts {
|
||||
|
||||
} // namespace handler_bts
|
||||
|
||||
}}} // namespace phantom::io_stream::proto_http
|
||||
14392
tests/cpp/jstracer.cpp
14392
tests/cpp/jstracer.cpp
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* May 28, 2008.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
* Mike Shaver <shaver@mozilla.org>
|
||||
* David Anderson <danderson@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include "nanojit/nanojit.h"
|
||||
|
||||
using namespace nanojit;
|
||||
|
||||
|
||||
void*
|
||||
nanojit::Allocator::allocChunk(size_t nbytes)
|
||||
{
|
||||
VMAllocator *vma = (VMAllocator*)this;
|
||||
JS_ASSERT(!vma->outOfMemory());
|
||||
void *p = malloc(nbytes);
|
||||
if (!p) {
|
||||
JS_ASSERT(nbytes < sizeof(vma->mReserve));
|
||||
vma->mOutOfMemory = true;
|
||||
p = (void*) &vma->mReserve[0];
|
||||
}
|
||||
vma->mSize += nbytes;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
nanojit::Allocator::freeChunk(void *p) {
|
||||
VMAllocator *vma = (VMAllocator*)this;
|
||||
if (p != &vma->mReserve[0])
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
nanojit::Allocator::postReset() {
|
||||
VMAllocator *vma = (VMAllocator*)this;
|
||||
vma->mOutOfMemory = false;
|
||||
vma->mSize = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nanojit::StackFilter::getTops(LIns* guard, int& spTop, int& rpTop)
|
||||
{
|
||||
VMSideExit* e = (VMSideExit*)guard->record()->exit;
|
||||
spTop = e->sp_adj;
|
||||
rpTop = e->rp_adj;
|
||||
}
|
||||
|
||||
class AdjustCallerGlobalTypesVisitor : public SlotVisitorBase
|
||||
{
|
||||
TraceRecorder &mRecorder;
|
||||
JSContext *mCx;
|
||||
nanojit::LirBuffer *mLirbuf;
|
||||
nanojit::LirWriter *mLir;
|
||||
JSTraceType *mTypeMap;
|
||||
public:
|
||||
AdjustCallerGlobalTypesVisitor(TraceRecorder &recorder,
|
||||
JSTraceType *typeMap) :
|
||||
mRecorder(recorder),
|
||||
mCx(mRecorder.cx),
|
||||
mLirbuf(mRecorder.lirbuf),
|
||||
mLir(mRecorder.lir),
|
||||
mTypeMap(typeMap)
|
||||
{}
|
||||
|
||||
JSTraceType* getTypeMap()
|
||||
{
|
||||
return mTypeMap;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
||||
visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) {
|
||||
LIns *ins = mRecorder.get(vp);
|
||||
bool isPromote = isPromoteInt(ins);
|
||||
if (isPromote && *mTypeMap == TT_DOUBLE) {
|
||||
mLir->insStorei(mRecorder.get(vp), mLirbuf->state,
|
||||
mRecorder.nativeGlobalOffset(vp));
|
||||
|
||||
/*
|
||||
* Aggressively undo speculation so the inner tree will compile
|
||||
* if this fails.
|
||||
*/
|
||||
oracle.markGlobalSlotUndemotable(mCx, slot);
|
||||
}
|
||||
JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32));
|
||||
++mTypeMap;
|
||||
}
|
||||
};
|
||||
|
||||
class AdjustCallerStackTypesVisitor : public SlotVisitorBase
|
||||
{
|
||||
TraceRecorder &mRecorder;
|
||||
JSContext *mCx;
|
||||
nanojit::LirBuffer *mLirbuf;
|
||||
nanojit::LirWriter *mLir;
|
||||
unsigned mSlotnum;
|
||||
JSTraceType *mTypeMap;
|
||||
public:
|
||||
AdjustCallerStackTypesVisitor(TraceRecorder &recorder,
|
||||
JSTraceType *typeMap) :
|
||||
mRecorder(recorder),
|
||||
mCx(mRecorder.cx),
|
||||
mLirbuf(mRecorder.lirbuf),
|
||||
mLir(mRecorder.lir),
|
||||
mSlotnum(0),
|
||||
mTypeMap(typeMap)
|
||||
{}
|
||||
|
||||
JSTraceType* getTypeMap()
|
||||
{
|
||||
return mTypeMap;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
||||
visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
LIns *ins = mRecorder.get(vp);
|
||||
bool isPromote = isPromoteInt(ins);
|
||||
if (isPromote && *mTypeMap == TT_DOUBLE) {
|
||||
mLir->insStorei(mRecorder.get(vp), mLirbuf->sp,
|
||||
-mRecorder.treeInfo->nativeStackBase +
|
||||
mRecorder.nativeStackOffset(vp));
|
||||
|
||||
/*
|
||||
* Aggressively undo speculation so the inner tree will compile
|
||||
* if this fails.
|
||||
*/
|
||||
oracle.markStackSlotUndemotable(mCx, mSlotnum);
|
||||
}
|
||||
JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32));
|
||||
++vp;
|
||||
++mTypeMap;
|
||||
++mSlotnum;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#if defined NJ_VERBOSE
|
||||
void
|
||||
nanojit::LirNameMap::formatGuard(LIns *i, char *out)
|
||||
{
|
||||
VMSideExit *x;
|
||||
|
||||
x = (VMSideExit *)i->record()->exit;
|
||||
sprintf(out,
|
||||
"%s: %s %s -> pc=%p imacpc=%p sp%+ld rp%+ld (GuardID=%03d)",
|
||||
formatRef(i),
|
||||
lirNames[i->opcode()],
|
||||
i->oprnd1() ? formatRef(i->oprnd1()) : "",
|
||||
(void *)x->pc,
|
||||
(void *)x->imacpc,
|
||||
(long int)x->sp_adj,
|
||||
(long int)x->rp_adj,
|
||||
i->record()->profGuardID);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassDescription(
|
||||
char **result,
|
||||
int foo,
|
||||
bool blah
|
||||
)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int foo;
|
||||
@@ -1,6 +0,0 @@
|
||||
void*
|
||||
Foo::bar(int i,
|
||||
const char const * const * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,310 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla.
|
||||
*
|
||||
* The Initial Developer of the Original Code is IBM Corporation.
|
||||
* Portions created by IBM Corporation are Copyright (C) 2003
|
||||
* IBM Corporation. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* IBM Corp.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIEventTarget.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prclist.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
// NSPR_LOG_MODULES=nsIOThreadPool:5
|
||||
//
|
||||
static PRLogModuleInfo *gIOThreadPoolLog = nsnull;
|
||||
#endif
|
||||
#define LOG(args) PR_LOG(gIOThreadPoolLog, PR_LOG_DEBUG, args)
|
||||
|
||||
// this number specifies the maximum number of threads.
|
||||
#define MAX_THREADS 4
|
||||
|
||||
// this number specifies how long to wait before killing an idle thread. it's
|
||||
// important to pick a large enough value here to minimize thread churn.
|
||||
#define IDLE_TIMEOUT PR_SecondsToInterval(60)
|
||||
|
||||
#define PLEVENT_FROM_LINK(_link) \
|
||||
((PLEvent*) ((char*) (_link) - offsetof(PLEvent, link)))
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// pool of joinable threads used for general purpose i/o tasks
|
||||
//
|
||||
// the main entry point to this class is nsIEventTarget. events posted to
|
||||
// the thread pool are dispatched on one of the threads. a variable number
|
||||
// of threads are maintained. the threads die off if they remain idle for
|
||||
// more than THREAD_IDLE_TIMEOUT. the thread pool shuts down when it receives
|
||||
// the "xpcom-shutdown" event.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsIOThreadPool : public nsIEventTarget
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
virtual ~nsIOThreadPool();
|
||||
|
||||
PR_STATIC_CALLBACK(void) ThreadFunc(void *);
|
||||
|
||||
// mLock protects all (exceptions during Init and Shutdown)
|
||||
PRLock *mLock;
|
||||
PRCondVar *mIdleThreadCV; // notified to wake up an idle thread
|
||||
PRCondVar *mExitThreadCV; // notified when a thread exits
|
||||
PRUint32 mNumThreads; // number of active + idle threads
|
||||
PRUint32 mNumIdleThreads; // number of idle threads
|
||||
PRCList mEventQ; // queue of PLEvent structs
|
||||
PRBool mShutdown; // set to true if shutting down
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsIOThreadPool, nsIEventTarget, nsIObserver)
|
||||
|
||||
nsresult
|
||||
nsIOThreadPool::Init()
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gIOThreadPoolLog)
|
||||
gIOThreadPoolLog = PR_NewLogModule("nsIOThreadPool");
|
||||
#endif
|
||||
|
||||
mNumThreads = 0;
|
||||
mNumIdleThreads = 0;
|
||||
mShutdown = PR_FALSE;
|
||||
|
||||
mLock = PR_NewLock();
|
||||
if (!mLock)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mIdleThreadCV = PR_NewCondVar(mLock);
|
||||
if (!mIdleThreadCV)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mExitThreadCV = PR_NewCondVar(mLock);
|
||||
if (!mExitThreadCV)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PR_INIT_CLIST(&mEventQ);
|
||||
|
||||
// we want to shutdown the i/o thread pool at xpcom-shutdown time...
|
||||
nsCOMPtr<nsIObserverService> os = do_GetService("@mozilla.org/observer-service;1");
|
||||
if (os)
|
||||
os->AddObserver(this, "xpcom-shutdown", PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIOThreadPool::~nsIOThreadPool()
|
||||
{
|
||||
LOG(("Destroying nsIOThreadPool @%p\n", this));
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mEventQ), "leaking events");
|
||||
NS_ASSERTION(mNumThreads == 0, "leaking thread(s)");
|
||||
#endif
|
||||
|
||||
if (mIdleThreadCV)
|
||||
PR_DestroyCondVar(mIdleThreadCV);
|
||||
if (mExitThreadCV)
|
||||
PR_DestroyCondVar(mExitThreadCV);
|
||||
if (mLock)
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
void
|
||||
nsIOThreadPool::Shutdown()
|
||||
{
|
||||
LOG(("nsIOThreadPool::Shutdown\n"));
|
||||
|
||||
// synchronize with background threads...
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
mShutdown = PR_TRUE;
|
||||
|
||||
PR_NotifyAllCondVar(mIdleThreadCV);
|
||||
|
||||
while (mNumThreads != 0)
|
||||
PR_WaitCondVar(mExitThreadCV, PR_INTERVAL_NO_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOThreadPool::PostEvent(PLEvent *event)
|
||||
{
|
||||
LOG(("nsIOThreadPool::PostEvent [event=%p]\n", event));
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
// if we are shutting down, then prevent additional events from being
|
||||
// added to the queue...
|
||||
if (mShutdown)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
PR_APPEND_LINK(&event->link, &mEventQ);
|
||||
|
||||
// now, look for an available idle thread...
|
||||
if (mNumIdleThreads)
|
||||
PR_NotifyCondVar(mIdleThreadCV); // wake up an idle thread
|
||||
|
||||
// or, try to create a new thread unless we have reached our maximum...
|
||||
else if (mNumThreads < MAX_THREADS) {
|
||||
NS_ADDREF_THIS(); // the thread owns a reference to us
|
||||
mNumThreads++;
|
||||
PRThread *thread = PR_CreateThread(PR_USER_THREAD,
|
||||
ThreadFunc,
|
||||
this,
|
||||
PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD,
|
||||
PR_UNJOINABLE_THREAD,
|
||||
0);
|
||||
if (!thread) {
|
||||
NS_RELEASE_THIS();
|
||||
mNumThreads--;
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
// else, we expect one of the active threads to process the event queue.
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOThreadPool::IsOnCurrentThread(PRBool *result)
|
||||
{
|
||||
// no one should be calling this method. if this assertion gets hit,
|
||||
// then we need to think carefully about what this method should be
|
||||
// returning.
|
||||
NS_NOTREACHED("nsIOThreadPool::IsOnCurrentThread");
|
||||
|
||||
// fudging this a bit since we actually cover several threads...
|
||||
*result = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOThreadPool::Observe(nsISupports *, const char *topic, const PRUnichar *)
|
||||
{
|
||||
NS_ASSERTION(strcmp(topic, "xpcom-shutdown") == 0, "unexpected topic");
|
||||
Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsIOThreadPool::ThreadFunc(void *arg)
|
||||
{
|
||||
nsIOThreadPool *pool = (nsIOThreadPool *) arg;
|
||||
|
||||
LOG(("entering ThreadFunc\n"));
|
||||
|
||||
{
|
||||
nsAutoLock lock(pool->mLock);
|
||||
|
||||
for (;;) {
|
||||
PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT;
|
||||
//
|
||||
// wait for one or more of the following to occur:
|
||||
// (1) the event queue has an event to process
|
||||
// (2) the shutdown flag has been set
|
||||
// (3) the thread has been idle for too long
|
||||
//
|
||||
// PR_WaitCondVar will return when any of these conditions is true.
|
||||
//
|
||||
while (PR_CLIST_IS_EMPTY(&pool->mEventQ) && !pool->mShutdown) {
|
||||
pool->mNumIdleThreads++;
|
||||
PR_WaitCondVar(pool->mIdleThreadCV, timeout);
|
||||
pool->mNumIdleThreads--;
|
||||
|
||||
PRIntervalTime delta = PR_IntervalNow() - start;
|
||||
if (delta >= timeout)
|
||||
break;
|
||||
timeout -= delta;
|
||||
start += delta;
|
||||
}
|
||||
|
||||
// if the queue is still empty, then kill this thread (either we
|
||||
// are shutting down or the thread exceeded the idle timeout)...
|
||||
if (PR_CLIST_IS_EMPTY(&pool->mEventQ))
|
||||
break;
|
||||
|
||||
// handle one event at a time: we don't want this one thread to hog
|
||||
// all the events while other threads may be able to help out ;-)
|
||||
do {
|
||||
PLEvent *event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&pool->mEventQ));
|
||||
PR_REMOVE_AND_INIT_LINK(&event->link);
|
||||
|
||||
LOG(("event:%p\n", event));
|
||||
|
||||
// release lock!
|
||||
lock.unlock();
|
||||
PL_HandleEvent(event);
|
||||
lock.lock();
|
||||
}
|
||||
while (!PR_CLIST_IS_EMPTY(&pool->mEventQ));
|
||||
}
|
||||
|
||||
// thread is going away...
|
||||
pool->mNumThreads--;
|
||||
PR_NotifyCondVar(pool->mExitThreadCV);
|
||||
}
|
||||
|
||||
// release our reference to the pool
|
||||
NS_RELEASE(pool);
|
||||
|
||||
LOG(("leaving ThreadFunc\n"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_METHOD
|
||||
net_NewIOThreadPool(nsISupports *outer, REFNSIID iid, void **result)
|
||||
{
|
||||
nsIOThreadPool *pool = new nsIOThreadPool();
|
||||
if (!pool)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(pool);
|
||||
nsresult rv = pool->Init();
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = pool->QueryInterface(iid, result);
|
||||
NS_RELEASE(pool);
|
||||
return rv;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,702 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "timelog.h"
|
||||
|
||||
#include "nsThread.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prlog.h"
|
||||
#include "nsThreadUtilsInternal.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *sLog = PR_NewLogModule("nsThread");
|
||||
#endif
|
||||
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
||||
|
||||
NS_DECL_CI_INTERFACE_GETTER(nsThread)
|
||||
|
||||
nsIThreadObserver* nsThread::sGlobalObserver;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Because we do not have our own nsIFactory, we have to implement nsIClassInfo
|
||||
// somewhat manually.
|
||||
|
||||
class nsThreadClassInfo : public nsIClassInfo {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED // no mRefCnt
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
||||
nsThreadClassInfo() {}
|
||||
};
|
||||
|
||||
static nsThreadClassInfo sThreadClassInfo;
|
||||
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::AddRef() { return 2; }
|
||||
NS_IMETHODIMP_(nsrefcnt) nsThreadClassInfo::Release() { return 1; }
|
||||
NS_IMPL_QUERY_INTERFACE1(nsThreadClassInfo, nsIClassInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetInterfaces(PRUint32 *count, nsIID ***array)
|
||||
{
|
||||
return NS_CI_INTERFACE_GETTER_NAME(nsThread)(count, array);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetHelperForLanguage(PRUint32 lang, nsISupports **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetContractID(char **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassDescription(char **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassID(nsCID **result)
|
||||
{
|
||||
*result = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetImplementationLanguage(PRUint32 *result)
|
||||
{
|
||||
*result = nsIProgrammingLanguage::CPLUSPLUS;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetFlags(PRUint32 *result)
|
||||
{
|
||||
*result = THREADSAFE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadClassInfo::GetClassIDNoAlloc(nsCID *result)
|
||||
{
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_THREADSAFE_ADDREF(nsThread)
|
||||
NS_IMPL_THREADSAFE_RELEASE(nsThread)
|
||||
NS_INTERFACE_MAP_BEGIN(nsThread)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThread)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIThreadInternal)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIEventTarget)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIThread)
|
||||
if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
|
||||
foundInterface = static_cast<nsIClassInfo*>(&sThreadClassInfo);
|
||||
} else
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CI_INTERFACE_GETTER4(nsThread, nsIThread, nsIThreadInternal,
|
||||
nsIEventTarget, nsISupportsPriority)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadStartupEvent : public nsRunnable {
|
||||
public:
|
||||
// Create a new thread startup object.
|
||||
static nsThreadStartupEvent *Create() {
|
||||
nsThreadStartupEvent *startup = new nsThreadStartupEvent();
|
||||
if (startup && startup->mMon)
|
||||
return startup;
|
||||
// Allocation failure
|
||||
delete startup;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// This method does not return until the thread startup object is in the
|
||||
// completion state.
|
||||
void Wait() {
|
||||
if (mInitialized) // Maybe avoid locking...
|
||||
return;
|
||||
nsAutoMonitor mon(mMon);
|
||||
while (!mInitialized)
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
// This method needs to be public to support older compilers (xlC_r on AIX).
|
||||
// It should be called directly as this class type is reference counted.
|
||||
virtual ~nsThreadStartupEvent() {
|
||||
if (mMon)
|
||||
nsAutoMonitor::DestroyMonitor(mMon);
|
||||
}
|
||||
|
||||
private:
|
||||
NS_IMETHOD Run() {
|
||||
nsAutoMonitor mon(mMon);
|
||||
mInitialized = PR_TRUE;
|
||||
mon.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsThreadStartupEvent()
|
||||
: mMon(nsAutoMonitor::NewMonitor("xpcom.threadstartup"))
|
||||
, mInitialized(PR_FALSE) {
|
||||
}
|
||||
|
||||
PRMonitor *mMon;
|
||||
PRBool mInitialized;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This event is responsible for notifying nsThread::Shutdown that it is time
|
||||
// to call PR_JoinThread.
|
||||
class nsThreadShutdownAckEvent : public nsRunnable {
|
||||
public:
|
||||
nsThreadShutdownAckEvent(nsThreadShutdownContext *ctx)
|
||||
: mShutdownContext(ctx) {
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
mShutdownContext->shutdownAck = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsThreadShutdownContext *mShutdownContext;
|
||||
};
|
||||
|
||||
// This event is responsible for setting mShutdownContext
|
||||
class nsThreadShutdownEvent : public nsRunnable {
|
||||
public:
|
||||
nsThreadShutdownEvent(nsThread *thr, nsThreadShutdownContext *ctx)
|
||||
: mThread(thr), mShutdownContext(ctx) {
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
mThread->mShutdownContext = mShutdownContext;
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<nsThread> mThread;
|
||||
fprintf(logfp, "%s.%09ld: New Thread (%p)\n", out.str, out.nsec, (void *)self);
|
||||
|
||||
// Inform the ThreadManager
|
||||
nsThreadManager::get()->RegisterCurrentThread(self);
|
||||
|
||||
// Wait for and process startup event
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
if (!self->GetEvent(PR_TRUE, getter_AddRefs(event))) {
|
||||
NS_WARNING("failed waiting for thread startup event");
|
||||
return;
|
||||
}
|
||||
event->Run(); // unblocks nsThread::Init
|
||||
event = nsnull;
|
||||
|
||||
// Now, process incoming events...
|
||||
while (!self->ShuttingDown())
|
||||
NS_ProcessNextEvent(self);
|
||||
|
||||
// Do NS_ProcessPendingEvents but with special handling to set
|
||||
// mEventsAreDoomed atomically with the removal of the last event. The key
|
||||
// invariant here is that we will never permit PutEvent to succeed if the
|
||||
// event would be left in the queue after our final call to
|
||||
// NS_ProcessPendingEvents.
|
||||
while (PR_TRUE) {
|
||||
{
|
||||
nsAutoLock lock(self->mLock);
|
||||
if (!self->mEvents->HasPendingEvent()) {
|
||||
// No events in the queue, so we will stop now. Don't let any more
|
||||
// events be added, since they won't be processed. It is critical
|
||||
// that no PutEvent can occur between testing that the event queue is
|
||||
// empty and setting mEventsAreDoomed!
|
||||
self->mEventsAreDoomed = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NS_ProcessPendingEvents(self);
|
||||
}
|
||||
|
||||
// Inform the threadmanager that this thread is going away
|
||||
nsThreadManager::get()->UnregisterCurrentThread(self);
|
||||
|
||||
// Dispatch shutdown ACK
|
||||
event = new nsThreadShutdownAckEvent(self->mShutdownContext);
|
||||
self->mShutdownContext->joiningThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
// Release any observer of the thread here.
|
||||
self->SetObserver(nsnull);
|
||||
|
||||
NS_RELEASE(self);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
nsThread::nsThread()
|
||||
: mLock(PR_NewLock())
|
||||
, mEvents(&mEventsRoot)
|
||||
, mPriority(PRIORITY_NORMAL)
|
||||
, mThread(nsnull)
|
||||
, mRunningEvent(0)
|
||||
, mShutdownContext(nsnull)
|
||||
, mShutdownRequired(PR_FALSE)
|
||||
, mEventsAreDoomed(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsThread::~nsThread()
|
||||
{
|
||||
if (mLock)
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThread::Init()
|
||||
{
|
||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
struct logtime out;
|
||||
get_log_time(&out);
|
||||
fprintf(logfp, "%s.%09ld: Thread (%p) Init() start\n", out.str, out.nsec, (void *)this);
|
||||
|
||||
// spawn thread and wait until it is fully setup
|
||||
nsRefPtr<nsThreadStartupEvent> startup = nsThreadStartupEvent::Create();
|
||||
NS_ENSURE_TRUE(startup, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
mShutdownRequired = PR_TRUE;
|
||||
|
||||
// ThreadFunc is responsible for setting mThread
|
||||
PRThread *thr = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0);
|
||||
if (!thr) {
|
||||
NS_RELEASE_THIS();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// ThreadFunc will wait for this event to be run before it tries to access
|
||||
// mThread. By delaying insertion of this event into the queue, we ensure
|
||||
// that mThread is set properly.
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
mEvents->PutEvent(startup);
|
||||
}
|
||||
|
||||
// Wait for thread to call ThreadManager::SetupCurrentThread, which completes
|
||||
// initialization of ThreadFunc.
|
||||
startup->Wait();
|
||||
|
||||
get_log_time(&out);
|
||||
fprintf(logfp, "%s.%09ld: Thread (%p) Init() end\n", out.str, out.nsec, (void *)this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThread::InitCurrentThread()
|
||||
{
|
||||
NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
mThread = PR_GetCurrentThread();
|
||||
|
||||
nsThreadManager::get()->RegisterCurrentThread(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThread::PutEvent(nsIRunnable *event)
|
||||
{
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
if (mEventsAreDoomed) {
|
||||
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (!mEvents->PutEvent(event))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs = GetObserver();
|
||||
if (obs)
|
||||
obs->OnDispatchedEvent(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIEventTarget
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Dispatch(nsIRunnable *event, PRUint32 flags)
|
||||
{
|
||||
LOG(("THRD(%p) Dispatch [%p %x]\n", this, event, flags));
|
||||
|
||||
NS_ENSURE_ARG_POINTER(event);
|
||||
|
||||
if (flags & DISPATCH_SYNC) {
|
||||
nsThread *thread = nsThreadManager::get()->GetCurrentThread();
|
||||
NS_ENSURE_STATE(thread);
|
||||
|
||||
// XXX we should be able to do something better here... we should
|
||||
// be able to monitor the slot occupied by this event and use
|
||||
// that to tell us when the event has been processed.
|
||||
|
||||
nsRefPtr<nsThreadSyncDispatch> wrapper =
|
||||
new nsThreadSyncDispatch(thread, event);
|
||||
if (!wrapper)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsresult rv = PutEvent(wrapper);
|
||||
// Don't wait for the event to finish if we didn't dispatch it...
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
while (wrapper->IsPending())
|
||||
NS_ProcessNextEvent(thread);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(flags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
|
||||
return PutEvent(event);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::IsOnCurrentThread(PRBool *result)
|
||||
{
|
||||
*result = (PR_GetCurrentThread() == mThread);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIThread
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPRThread(PRThread **result)
|
||||
{
|
||||
*result = mThread;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::Shutdown()
|
||||
{
|
||||
LOG(("THRD(%p) shutdown\n", this));
|
||||
|
||||
// XXX If we make this warn, then we hit that warning at xpcom shutdown while
|
||||
// shutting down a thread in a thread pool. That happens b/c the thread
|
||||
// in the thread pool is already shutdown by the thread manager.
|
||||
if (!mThread)
|
||||
return NS_OK;
|
||||
|
||||
NS_ENSURE_STATE(mThread != PR_GetCurrentThread());
|
||||
|
||||
// Prevent multiple calls to this method
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
if (!mShutdownRequired)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
mShutdownRequired = PR_FALSE;
|
||||
}
|
||||
|
||||
nsThreadShutdownContext context;
|
||||
context.joiningThread = nsThreadManager::get()->GetCurrentThread();
|
||||
context.shutdownAck = PR_FALSE;
|
||||
|
||||
// Set mShutdownContext and wake up the thread in case it is waiting for
|
||||
// events to process.
|
||||
nsCOMPtr<nsIRunnable> event = new nsThreadShutdownEvent(this, &context);
|
||||
if (!event)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// XXXroc What if posting the event fails due to OOM?
|
||||
PutEvent(event);
|
||||
|
||||
// We could still end up with other events being added after the shutdown
|
||||
// task, but that's okay because we process pending events in ThreadFunc
|
||||
// after setting mShutdownContext just before exiting.
|
||||
|
||||
// Process events on the current thread until we receive a shutdown ACK.
|
||||
while (!context.shutdownAck)
|
||||
NS_ProcessNextEvent(context.joiningThread);
|
||||
|
||||
// Now, it should be safe to join without fear of dead-locking.
|
||||
|
||||
PR_JoinThread(mThread);
|
||||
mThread = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
NS_ASSERTION(!mObserver, "Should have been cleared at shutdown!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::HasPendingEvents(PRBool *result)
|
||||
{
|
||||
NS_ENSURE_STATE(PR_GetCurrentThread() == mThread);
|
||||
|
||||
*result = mEvents->GetEvent(PR_FALSE, nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)
|
||||
{
|
||||
struct logtime out;
|
||||
get_log_time(&out);
|
||||
fprintf(logfp, "%s.%09ld: Thread (%p) ProcessNextEvent [%u %u]\n",
|
||||
out.str,
|
||||
out.nsec,
|
||||
(void *)this,
|
||||
mayWait,
|
||||
mRunningEvent);
|
||||
|
||||
LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, mayWait, mRunningEvent));
|
||||
|
||||
NS_ENSURE_STATE(PR_GetCurrentThread() == mThread);
|
||||
|
||||
PRBool notifyGlobalObserver = (sGlobalObserver != nsnull);
|
||||
if (notifyGlobalObserver)
|
||||
sGlobalObserver->OnProcessNextEvent(this, mayWait && !ShuttingDown(),
|
||||
mRunningEvent);
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> obs = mObserver;
|
||||
if (obs)
|
||||
obs->OnProcessNextEvent(this, mayWait && !ShuttingDown(), mRunningEvent);
|
||||
|
||||
++mRunningEvent;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
{
|
||||
// Scope for |event| to make sure that its destructor fires while
|
||||
// mRunningEvent has been incremented, since that destructor can
|
||||
// also do work.
|
||||
|
||||
// If we are shutting down, then do not wait for new events.
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
mEvents->GetEvent(mayWait && !ShuttingDown(), getter_AddRefs(event));
|
||||
|
||||
*result = (event.get() != nsnull);
|
||||
|
||||
if (event) {
|
||||
get_log_time(&out);
|
||||
fprintf(logfp, "%s.%09ld: Thread (%p) running [%p]\n",
|
||||
out.str,
|
||||
out.nsec,
|
||||
(void *)this,
|
||||
(void *)event.get());
|
||||
LOG(("THRD(%p) running [%p]\n", this, event.get()));
|
||||
event->Run();
|
||||
} else if (mayWait) {
|
||||
NS_ASSERTION(ShuttingDown(),
|
||||
"This should only happen when shutting down");
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
get_log_time(&out);
|
||||
fprintf(logfp, "%s.%09ld: Thread (%p) running finished [%p]\n",
|
||||
out.str,
|
||||
out.nsec,
|
||||
(void *)this,
|
||||
(void *)event.get());
|
||||
}
|
||||
|
||||
--mRunningEvent;
|
||||
if (obs)
|
||||
obs->AfterProcessNextEvent(this, mRunningEvent);
|
||||
|
||||
if (notifyGlobalObserver && sGlobalObserver)
|
||||
sGlobalObserver->AfterProcessNextEvent(this, mRunningEvent);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsISupportsPriority
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetPriority(PRInt32 *priority)
|
||||
{
|
||||
*priority = mPriority;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetPriority(PRInt32 priority)
|
||||
{
|
||||
NS_ENSURE_STATE(mThread);
|
||||
|
||||
// NSPR defines the following four thread priorities:
|
||||
// PR_PRIORITY_LOW
|
||||
// PR_PRIORITY_NORMAL
|
||||
// PR_PRIORITY_HIGH
|
||||
// PR_PRIORITY_URGENT
|
||||
// We map the priority values defined on nsISupportsPriority to these values.
|
||||
|
||||
mPriority = priority;
|
||||
|
||||
PRThreadPriority pri;
|
||||
if (mPriority <= PRIORITY_HIGHEST) {
|
||||
pri = PR_PRIORITY_URGENT;
|
||||
} else if (mPriority < PRIORITY_NORMAL) {
|
||||
pri = PR_PRIORITY_HIGH;
|
||||
} else if (mPriority > PRIORITY_NORMAL) {
|
||||
pri = PR_PRIORITY_LOW;
|
||||
} else {
|
||||
pri = PR_PRIORITY_NORMAL;
|
||||
}
|
||||
PR_SetThreadPriority(mThread, pri);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::AdjustPriority(PRInt32 delta)
|
||||
{
|
||||
return SetPriority(mPriority + delta);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIThreadInternal
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::GetObserver(nsIThreadObserver **obs)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
NS_IF_ADDREF(*obs = mObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::SetObserver(nsIThreadObserver *obs)
|
||||
{
|
||||
NS_ENSURE_STATE(PR_GetCurrentThread() == mThread);
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
mObserver = obs;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::PushEventQueue(nsIThreadEventFilter *filter)
|
||||
{
|
||||
nsChainedEventQueue *queue = new nsChainedEventQueue(filter);
|
||||
if (!queue || !queue->IsInitialized()) {
|
||||
delete queue;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
queue->mNext = mEvents;
|
||||
mEvents = queue;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::PopEventQueue()
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
// Make sure we do not pop too many!
|
||||
NS_ENSURE_STATE(mEvents != &mEventsRoot);
|
||||
|
||||
nsChainedEventQueue *queue = mEvents;
|
||||
mEvents = mEvents->mNext;
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
while (queue->GetEvent(PR_FALSE, getter_AddRefs(event)))
|
||||
mEvents->PutEvent(event);
|
||||
|
||||
delete queue;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsThread::nsChainedEventQueue::PutEvent(nsIRunnable *event)
|
||||
{
|
||||
PRBool val;
|
||||
if (!mFilter || mFilter->AcceptEvent(event)) {
|
||||
val = mQueue.PutEvent(event);
|
||||
} else {
|
||||
val = mNext->PutEvent(event);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadSyncDispatch::Run()
|
||||
{
|
||||
if (mSyncTask) {
|
||||
mSyncTask->Run();
|
||||
mSyncTask = nsnull;
|
||||
// unblock the origin thread
|
||||
mOrigin->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_SetGlobalThreadObserver(nsIThreadObserver* aObserver)
|
||||
{
|
||||
if (aObserver && nsThread::sGlobalObserver) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsThread::sGlobalObserver = aObserver;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2006
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Darin Fisher <darin@meer.net>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsThread_h__
|
||||
#define nsThread_h__
|
||||
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsEventQueue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
// A native thread
|
||||
class nsThread : public nsIThreadInternal, public nsISupportsPriority
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEVENTTARGET
|
||||
NS_DECL_NSITHREAD
|
||||
NS_DECL_NSITHREADINTERNAL
|
||||
NS_DECL_NSISUPPORTSPRIORITY
|
||||
|
||||
nsThread();
|
||||
|
||||
// Initialize this as a wrapper for a new PRThread.
|
||||
nsresult Init();
|
||||
|
||||
// Initialize this as a wrapper for the current PRThread.
|
||||
nsresult InitCurrentThread();
|
||||
|
||||
// The PRThread corresponding to this thread.
|
||||
PRThread *GetPRThread() { return mThread; }
|
||||
|
||||
// If this flag is true, then the nsThread was created using
|
||||
// nsIThreadManager::NewThread.
|
||||
PRBool ShutdownRequired() { return mShutdownRequired; }
|
||||
|
||||
// The global thread observer
|
||||
static nsIThreadObserver* sGlobalObserver;
|
||||
|
||||
private:
|
||||
friend class nsThreadShutdownEvent;
|
||||
|
||||
~nsThread();
|
||||
|
||||
PRBool ShuttingDown() { return mShutdownContext != nsnull; }
|
||||
|
||||
static void ThreadFunc(void *arg);
|
||||
|
||||
// Helper
|
||||
already_AddRefed<nsIThreadObserver> GetObserver() {
|
||||
nsIThreadObserver *obs;
|
||||
nsThread::GetObserver(&obs);
|
||||
return already_AddRefed<nsIThreadObserver>(obs);
|
||||
}
|
||||
|
||||
// Wrappers for event queue methods:
|
||||
PRBool GetEvent(PRBool mayWait, nsIRunnable **event) {
|
||||
return mEvents->GetEvent(mayWait, event);
|
||||
}
|
||||
nsresult PutEvent(nsIRunnable *event);
|
||||
|
||||
// Wrapper for nsEventQueue that supports chaining.
|
||||
class nsChainedEventQueue {
|
||||
public:
|
||||
nsChainedEventQueue(nsIThreadEventFilter *filter = nsnull)
|
||||
: mNext(nsnull), mFilter(filter) {
|
||||
}
|
||||
|
||||
PRBool IsInitialized() {
|
||||
return mQueue.IsInitialized();
|
||||
}
|
||||
|
||||
PRBool GetEvent(PRBool mayWait, nsIRunnable **event) {
|
||||
return mQueue.GetEvent(mayWait, event);
|
||||
}
|
||||
|
||||
PRBool PutEvent(nsIRunnable *event);
|
||||
|
||||
PRBool HasPendingEvent() {
|
||||
return mQueue.HasPendingEvent();
|
||||
}
|
||||
|
||||
class nsChainedEventQueue *mNext;
|
||||
private:
|
||||
nsCOMPtr<nsIThreadEventFilter> mFilter;
|
||||
nsEventQueue mQueue;
|
||||
};
|
||||
|
||||
// This lock protects access to mObserver, mEvents and mEventsAreDoomed.
|
||||
// All of those fields are only modified on the thread itself (never from
|
||||
// another thread). This means that we can avoid holding the lock while
|
||||
// using mObserver and mEvents on the thread itself. When calling PutEvent
|
||||
// on mEvents, we have to hold the lock to synchronize with PopEventQueue.
|
||||
PRLock *mLock;
|
||||
|
||||
nsCOMPtr<nsIThreadObserver> mObserver;
|
||||
|
||||
nsChainedEventQueue *mEvents; // never null
|
||||
nsChainedEventQueue mEventsRoot;
|
||||
|
||||
PRInt32 mPriority;
|
||||
PRThread *mThread;
|
||||
PRUint32 mRunningEvent; // counter
|
||||
|
||||
struct nsThreadShutdownContext *mShutdownContext;
|
||||
|
||||
PRPackedBool mShutdownRequired;
|
||||
PRPackedBool mShutdownPending;
|
||||
// Set to true when events posted to this thread will never run.
|
||||
PRPackedBool mEventsAreDoomed;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsThreadSyncDispatch : public nsRunnable {
|
||||
public:
|
||||
nsThreadSyncDispatch(nsIThread *origin, nsIRunnable *task)
|
||||
: mOrigin(origin), mSyncTask(task) {
|
||||
}
|
||||
|
||||
PRBool IsPending() {
|
||||
return mSyncTask != nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
nsCOMPtr<nsIThread> mOrigin;
|
||||
nsCOMPtr<nsIRunnable> mSyncTask;
|
||||
};
|
||||
|
||||
#endif // nsThread_h__
|
||||
@@ -1,46 +0,0 @@
|
||||
namespace {
|
||||
struct nsThreadShutdownContext {
|
||||
nsThread *joiningThread;
|
||||
PRBool shutdownAck;
|
||||
union {
|
||||
int a;
|
||||
int b;
|
||||
union {
|
||||
char f;
|
||||
char g;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct teststruct {
|
||||
char foo;
|
||||
union {
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
short int i = 0;
|
||||
|
||||
class Testclass
|
||||
{
|
||||
int j;
|
||||
|
||||
public:
|
||||
|
||||
Testclass();
|
||||
~Testclass();
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
string str = "";
|
||||
class FooClass
|
||||
{
|
||||
FooClass();
|
||||
};
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,558 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIComponentRegistrar.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nspr.h"
|
||||
#include "prmon.h"
|
||||
|
||||
#include "nsITestProxy.h"
|
||||
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIProxyObjectManager.h"
|
||||
#include "nsIThreadPool.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
static PRLogModuleInfo *sLog = PR_NewLogModule("Test");
|
||||
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
|
||||
#else
|
||||
#define LOG(args) printf args
|
||||
#endif
|
||||
|
||||
namespace proxytests {
|
||||
|
||||
static nsresult
|
||||
GetThreadFromPRThread(PRThread *prthread, nsIThread **result)
|
||||
{
|
||||
LOG(("TEST: GetThreadFromPRThread [%p]\n", prthread));
|
||||
|
||||
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
|
||||
NS_ENSURE_STATE(tm);
|
||||
return tm->GetThreadFromPRThread(prthread, result);
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* nsTestXPCFoo */
|
||||
/***************************************************************************/
|
||||
class nsTestXPCFoo : public nsITestProxy
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval);
|
||||
NS_IMETHOD Test2();
|
||||
NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2);
|
||||
|
||||
nsTestXPCFoo();
|
||||
};
|
||||
|
||||
nsTestXPCFoo::nsTestXPCFoo()
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsTestXPCFoo, nsITestProxy)
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Test Called successfully! Party on...\n", p1));
|
||||
*retval = p1+p2;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test2()
|
||||
{
|
||||
LOG(("TEST: The quick brown netscape jumped over the old lazy ie..\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo::Test3(nsISupports *p1, nsISupports **p2)
|
||||
{
|
||||
if (p1 != nsnull)
|
||||
{
|
||||
nsITestProxy *test;
|
||||
|
||||
p1->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test);
|
||||
|
||||
test->Test2();
|
||||
PRInt32 a;
|
||||
test->Test( 1, 2, &a);
|
||||
LOG(("TEST: \n1+2=%d\n",a));
|
||||
}
|
||||
|
||||
|
||||
*p2 = new nsTestXPCFoo();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/* nsTestXPCFoo2 */
|
||||
/***************************************************************************/
|
||||
class nsTestXPCFoo2 : public nsITestProxy
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Test(PRInt32 p1, PRInt32 p2, PRInt32* retval);
|
||||
NS_IMETHOD Test2();
|
||||
NS_IMETHOD Test3(nsISupports *p1, nsISupports **p2);
|
||||
|
||||
nsTestXPCFoo2();
|
||||
};
|
||||
|
||||
nsTestXPCFoo2::nsTestXPCFoo2()
|
||||
{
|
||||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsTestXPCFoo2, nsITestProxy)
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test(PRInt32 p1, PRInt32 p2, PRInt32* retval)
|
||||
{
|
||||
LOG(("TEST: calling back to caller!\n"));
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
LOG(("TEST: ProxyObjectManager: %p \n", (void *) manager.get()));
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
GetThreadFromPRThread((PRThread *) p1, getter_AddRefs(thread));
|
||||
NS_ENSURE_STATE(thread);
|
||||
|
||||
nsCOMPtr<nsITestProxy> proxyObject;
|
||||
manager->GetProxyForObject(thread, NS_GET_IID(nsITestProxy), this, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
proxyObject->Test3(nsnull, nsnull);
|
||||
|
||||
LOG(("TEST: Deleting Proxy Object\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test2()
|
||||
{
|
||||
LOG(("TEST: nsTestXPCFoo2::Test2() called\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsTestXPCFoo2::Test3(nsISupports *p1, nsISupports **p2)
|
||||
{
|
||||
LOG(("TEST: Got called"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
struct ArgsStruct {
|
||||
nsIThread* thread;
|
||||
PRInt32 threadNumber;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// This will create two objects both descendants of a single IID.
|
||||
void TestCase_TwoClassesOneInterface(void *arg)
|
||||
{
|
||||
ArgsStruct *argsStruct = (ArgsStruct*) arg;
|
||||
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
printf("ProxyObjectManager: %p \n", (void *) manager.get());
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsITestProxy *proxyObject2;
|
||||
|
||||
nsTestXPCFoo* foo = new nsTestXPCFoo();
|
||||
nsTestXPCFoo2* foo2 = new nsTestXPCFoo2();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
PR_ASSERT(foo2);
|
||||
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo2, NS_PROXY_SYNC, (void**)&proxyObject2);
|
||||
|
||||
|
||||
|
||||
if (proxyObject && proxyObject2)
|
||||
{
|
||||
// release ownership of the real object.
|
||||
|
||||
PRInt32 a;
|
||||
nsresult rv;
|
||||
PRInt32 threadNumber = argsStruct->threadNumber;
|
||||
|
||||
printf("Deleting real Object (%d)\n", threadNumber);
|
||||
NS_RELEASE(foo);
|
||||
|
||||
printf("Deleting real Object 2 (%d)\n", threadNumber);
|
||||
NS_RELEASE(foo2);
|
||||
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject->Test.\n", threadNumber);
|
||||
rv = proxyObject->Test(threadNumber, 0, &a);
|
||||
printf("Thread (%d) error: %d.\n", threadNumber, rv);
|
||||
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject->Test2.\n", threadNumber);
|
||||
rv = proxyObject->Test2();
|
||||
printf("Thread (%d) error: %d.\n", threadNumber, rv);
|
||||
|
||||
printf("Thread (%d) Prior to calling proxyObject2->Test2.\n", threadNumber);
|
||||
rv = proxyObject2->Test2();
|
||||
printf("Thread (%d) proxyObject2 error: %d.\n", threadNumber, rv);
|
||||
|
||||
printf("Deleting Proxy Object (%d)\n", threadNumber );
|
||||
NS_RELEASE(proxyObject);
|
||||
|
||||
printf("Deleting Proxy Object 2 (%d)\n", threadNumber );
|
||||
NS_RELEASE(proxyObject2);
|
||||
}
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void TestCase_NestedLoop(nsIThread *thread, PRInt32 index)
|
||||
{
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
LOG(("TEST: ProxyObjectManager: %p\n", (void *) manager.get()));
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo2* foo = new nsTestXPCFoo2();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
|
||||
|
||||
manager->GetProxyForObject(thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
if (proxyObject)
|
||||
{
|
||||
// release ownership of the real object.
|
||||
|
||||
nsresult rv;
|
||||
|
||||
LOG(("TEST: Deleting real Object (%d)\n", index));
|
||||
NS_RELEASE(foo);
|
||||
|
||||
PRInt32 retval;
|
||||
|
||||
LOG(("TEST: Getting EventThread...\n"));
|
||||
|
||||
//nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
|
||||
PRThread *curThread = PR_GetCurrentThread();
|
||||
if (curThread)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Prior to calling proxyObject->Test.\n", index));
|
||||
rv = proxyObject->Test(NS_PTR_TO_INT32((void*)curThread), 0, &retval); // XXX broken on 64-bit arch
|
||||
LOG(("TEST: Thread (%d) proxyObject error: %x.\n", index, rv));
|
||||
|
||||
LOG(("TEST: Deleting Proxy Object (%d)\n", index));
|
||||
NS_RELEASE(proxyObject);
|
||||
}
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(1000) ); // If your thread goes away, your stack goes away. Only use ASYNC on calls that do not have out parameters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void TestCase_nsISupports(void *arg)
|
||||
{
|
||||
|
||||
ArgsStruct *argsStruct = (ArgsStruct*) arg;
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
PR_ASSERT(manager);
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo* foo = new nsTestXPCFoo();
|
||||
|
||||
PR_ASSERT(foo);
|
||||
|
||||
manager->GetProxyForObject(argsStruct->thread, NS_GET_IID(nsITestProxy), foo, NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
if (proxyObject != nsnull)
|
||||
{
|
||||
nsISupports *bISupports = nsnull, *cISupports = nsnull;
|
||||
|
||||
proxyObject->Test3(foo, &bISupports);
|
||||
proxyObject->Test3(bISupports, &cISupports);
|
||||
|
||||
nsITestProxy *test;
|
||||
bISupports->QueryInterface(NS_GET_IID(nsITestProxy), (void**)&test);
|
||||
|
||||
test->Test2();
|
||||
|
||||
NS_RELEASE(foo);
|
||||
NS_RELEASE(proxyObject);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
/* ProxyTest */
|
||||
/***************************************************************************/
|
||||
|
||||
class ProxyTest : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ProxyTest(PRThread *eventLoopThread, PRInt32 index)
|
||||
: mEventLoopThread(eventLoopThread)
|
||||
, mIndex(index)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
//TestCase_TwoClassesOneInterface(arg);
|
||||
//TestCase_nsISupports(arg);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
GetThreadFromPRThread(mEventLoopThread, getter_AddRefs(thread));
|
||||
TestCase_NestedLoop(thread, mIndex);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
PRThread *mEventLoopThread;
|
||||
PRInt32 mIndex;
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(ProxyTest, nsIRunnable)
|
||||
|
||||
class TestSyncProxyToSelf : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
LOG(("TEST: Verifing calling Proxy on eventQ thread.\n"));
|
||||
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
|
||||
nsITestProxy *proxyObject;
|
||||
nsTestXPCFoo *foo = new nsTestXPCFoo();
|
||||
NS_ENSURE_STATE(foo);
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
manager->GetProxyForObject(thread,
|
||||
NS_GET_IID(nsITestProxy), foo,
|
||||
NS_PROXY_SYNC, (void**)&proxyObject);
|
||||
|
||||
PRInt32 a;
|
||||
proxyObject->Test(1, 2, &a);
|
||||
proxyObject->Test2();
|
||||
|
||||
NS_RELEASE(proxyObject);
|
||||
delete foo;
|
||||
|
||||
LOG(("TEST: End of Verification calling Proxy on eventQ thread.\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(TestSyncProxyToSelf, nsIRunnable)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Test to make sure we can call methods on a "main thread only" object from
|
||||
// a background thread.
|
||||
|
||||
class MainThreadOnly : public nsIRunnable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD Run() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "method called on wrong thread");
|
||||
*mNumRuns -= 1;
|
||||
return NS_OK;
|
||||
}
|
||||
MainThreadOnly(PRUint32 *numRuns) : mNumRuns(numRuns) {}
|
||||
~MainThreadOnly() {
|
||||
NS_ASSERTION(NS_IsMainThread(), "method called on wrong thread");
|
||||
}
|
||||
PRBool IsDone() { return mNumRuns == 0; }
|
||||
private:
|
||||
PRUint32 *mNumRuns;
|
||||
};
|
||||
NS_IMPL_ISUPPORTS1(MainThreadOnly, nsIRunnable) // not threadsafe!
|
||||
|
||||
static nsresult
|
||||
RunApartmentTest()
|
||||
{
|
||||
LOG(("RunApartmentTest: start\n"));
|
||||
|
||||
const PRUint32 numDispatched = 160;
|
||||
|
||||
PRUint32 numCompleted = 0;
|
||||
nsCOMPtr<nsIRunnable> obj = new MainThreadOnly(&numCompleted);
|
||||
|
||||
nsCOMPtr<nsIProxyObjectManager> manager =
|
||||
do_GetService(NS_XPCOMPROXY_CONTRACTID);
|
||||
|
||||
nsCOMPtr<nsIRunnable> objProxy;
|
||||
manager->GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
|
||||
NS_GET_IID(nsIRunnable),
|
||||
obj,
|
||||
NS_PROXY_ASYNC,
|
||||
getter_AddRefs(objProxy));
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
NS_NewThread(getter_AddRefs(thread));
|
||||
|
||||
obj = nsnull;
|
||||
|
||||
nsCOMPtr<nsIThreadPool> pool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
|
||||
|
||||
pool->SetThreadLimit(8);
|
||||
for (PRUint32 i = 0; i < numDispatched; ++i)
|
||||
pool->Dispatch(objProxy, NS_DISPATCH_NORMAL);
|
||||
|
||||
objProxy = nsnull;
|
||||
|
||||
nsCOMPtr<nsIThread> curThread = do_GetCurrentThread();
|
||||
while (numCompleted < numDispatched) {
|
||||
NS_ProcessNextEvent(curThread);
|
||||
}
|
||||
|
||||
pool->Shutdown();
|
||||
|
||||
LOG(("RunApartmentTest: end\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace proxytests;
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int numberOfThreads = 1;
|
||||
|
||||
if (argc > 1)
|
||||
numberOfThreads = atoi(argv[1]);
|
||||
|
||||
NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
||||
|
||||
// Scope code so everything is destroyed before we run call NS_ShutdownXPCOM
|
||||
{
|
||||
nsCOMPtr<nsIComponentRegistrar> registrar;
|
||||
NS_GetComponentRegistrar(getter_AddRefs(registrar));
|
||||
registrar->AutoRegister(nsnull);
|
||||
|
||||
RunApartmentTest();
|
||||
|
||||
nsCOMPtr<nsIThread> eventLoopThread;
|
||||
NS_NewThread(getter_AddRefs(eventLoopThread));
|
||||
|
||||
nsCOMPtr<nsIRunnable> test = new TestSyncProxyToSelf();
|
||||
eventLoopThread->Dispatch(test, NS_DISPATCH_NORMAL);
|
||||
|
||||
PRThread *eventLoopPRThread;
|
||||
eventLoopThread->GetPRThread(&eventLoopPRThread);
|
||||
PR_ASSERT(eventLoopPRThread);
|
||||
|
||||
LOG(("TEST: Spawn Threads:\n"));
|
||||
nsCOMArray<nsIThread> threads;
|
||||
for (PRInt32 spawn = 0; spawn < numberOfThreads; spawn++)
|
||||
{
|
||||
test = new ProxyTest(eventLoopPRThread, spawn);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
NS_NewThread(getter_AddRefs(thread), test);
|
||||
|
||||
threads.AppendObject(thread);
|
||||
|
||||
LOG(("TEST: \tThread (%d) spawned\n", spawn));
|
||||
|
||||
PR_Sleep( PR_MillisecondsToInterval(250) );
|
||||
}
|
||||
|
||||
LOG(("TEST: All Threads Spawned.\n"));
|
||||
|
||||
LOG(("TEST: Wait for threads.\n"));
|
||||
for (PRInt32 i = 0; i < numberOfThreads; i++)
|
||||
{
|
||||
LOG(("TEST: Thread (%d) Join...\n", i));
|
||||
nsresult rv = threads[i]->Shutdown();
|
||||
LOG(("TEST: Thread (%d) Joined. (error: %x).\n", i, rv));
|
||||
}
|
||||
|
||||
LOG(("TEST: Shutting down event loop thread\n"));
|
||||
eventLoopThread->Shutdown();
|
||||
}
|
||||
|
||||
LOG(("TEST: Calling Cleanup.\n"));
|
||||
NS_ShutdownXPCOM(nsnull);
|
||||
|
||||
LOG(("TEST: Return zero.\n"));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
namespace Parser
|
||||
{
|
||||
namespace XXX
|
||||
{
|
||||
class Foobar
|
||||
{
|
||||
class Blah
|
||||
{
|
||||
class Bar
|
||||
{
|
||||
class Lalala
|
||||
{
|
||||
public:
|
||||
Foobar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
void*
|
||||
Parser::XXX::Foobar::wait(int i, const char const * const * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Foobar::non_nil()
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
int animal::moose::getFeet() //^2^
|
||||
{
|
||||
return fFeet;
|
||||
}
|
||||
|
||||
void animal::moose::doNothing() //^3^
|
||||
{
|
||||
animal::moose foo();
|
||||
|
||||
fFeet = N// -15-
|
||||
; // #15# ( "NAME1" "NAME2" "NAME3" )
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
// ICoder.h
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
class DataErrorException : ApplicationException
|
||||
{
|
||||
public DataErrorException(): base("Data Error") { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
class InvalidParamException : ApplicationException
|
||||
{
|
||||
public InvalidParamException(): base("Invalid Parameter") { }
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="SevenZip.DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
|
||||
public interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
public interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
public interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
class Encoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
|
||||
System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
uint _cacheSize;
|
||||
byte _cache;
|
||||
|
||||
long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
ShiftLow();
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
Low += Range;
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
Range = newBound;
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
class Decoder
|
||||
{
|
||||
public const uint kTopValue = (1 << 24);
|
||||
public uint Range;
|
||||
public uint Code;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
struct BitTreeEncoder
|
||||
{
|
||||
BitEncoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; )
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BitTreeDecoder
|
||||
{
|
||||
BitDecoder[] Models;
|
||||
int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
Models[i].Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
RangeCoder.Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= (bit << bitIndex);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
class
|
||||
POINT
|
||||
inherit
|
||||
ANY
|
||||
redefine
|
||||
out
|
||||
end
|
||||
create
|
||||
make, make_origin
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_x, a_y: INTEGER)
|
||||
-- Create with values `a_x' and `a_y'
|
||||
do
|
||||
set_x (a_x)
|
||||
set_y (a_y)
|
||||
ensure
|
||||
x_set: x = a_x
|
||||
y_set: y = a_y
|
||||
end
|
||||
|
||||
make_origin
|
||||
-- Create at origin
|
||||
do
|
||||
ensure
|
||||
x_set: x = 0
|
||||
y_set: y = 0
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
x: INTEGER assign set_x
|
||||
-- Horizontal axis coordinate
|
||||
|
||||
y: INTEGER assign set_y
|
||||
-- Vertical axis coordinate
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_x (a_x: INTEGER)
|
||||
-- Set `x' coordinate to `a_x'
|
||||
do
|
||||
x := a_x
|
||||
ensure
|
||||
x_set: x = a_x
|
||||
end
|
||||
|
||||
set_y (a_y: INTEGER)
|
||||
-- Set `y' coordinate to `a_y'
|
||||
do
|
||||
y := a_y
|
||||
ensure
|
||||
y_set: y = a_y
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
out: STRING
|
||||
-- Display as string
|
||||
do
|
||||
Result := "Point: x = " + x.out + " y = " + y.out
|
||||
end
|
||||
end
|
||||
@@ -1,34 +0,0 @@
|
||||
COMPILER ebnf.
|
||||
|
||||
CHARACTERS
|
||||
small = "abcdefghijklmnopqrstuvwxyz";
|
||||
big = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
alpha = small + big;
|
||||
dig = "0123456789";
|
||||
blank = CHR(9) + CHR(10) + CHR(32);
|
||||
noQuote = ANY - '"'.
|
||||
|
||||
COMMENTS
|
||||
FROM "(*" TO "*)" NESTED.
|
||||
|
||||
TOKENS
|
||||
Nonterminal = small {alpha | dig};
|
||||
Terminal = big {alpha | dig};
|
||||
White = blank {blank};
|
||||
String = '"' { noQuote } '"'.
|
||||
|
||||
IGNORE
|
||||
White + Comment.
|
||||
|
||||
PRODUCTIONS
|
||||
ebnf = {production} ".";
|
||||
production = Nonterminal "=" expr ";" ;
|
||||
expr = term {"|" term};
|
||||
term = factor {factor};
|
||||
factor = "{" expr "}"
|
||||
| "[" expr "]"
|
||||
| "(" expr ")"
|
||||
| Nonterminal | Terminal | String.
|
||||
|
||||
END ebnf.
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
Definitions.
|
||||
|
||||
Dig = [0-9]
|
||||
Big = [A-Z]
|
||||
Small = [a-z]
|
||||
WS = [\000-\s]
|
||||
|
||||
COMMENT = \(\*\(*([^*)]|[^*]\)|\*[^)])*\**\*\)
|
||||
STRING = "(\\\^.|\\.|[^"])*"
|
||||
QUOTE = '(\\\^.|\\.|[^'])*'
|
||||
|
||||
Rules.
|
||||
|
||||
({Small}({Small}|{Big}|{Dig}|_)*) : {token, {atom,YYline, YYtext}}.
|
||||
|
||||
({Big}({Small}|{Big}|{Dig}|_)*) : {token, special(YYtext, YYline)}.
|
||||
|
||||
({Dig}{Dig}*) : {token, {integer, YYline, list_to_integer(YYtext)}}.
|
||||
|
||||
%% string
|
||||
|
||||
{STRING} : %% Strip quotes.
|
||||
S = lists:sublist(YYtext, 2, length(YYtext) - 2),
|
||||
{token,{string,YYline,string_gen(S)}}.
|
||||
|
||||
{QUOTE} : %% Strip quotes.
|
||||
S = lists:sublist(YYtext, 2, length(YYtext) - 2),
|
||||
{token,{quote,YYline,string_gen(S)}}.
|
||||
|
||||
|
||||
{COMMENT} : .
|
||||
|
||||
|
||||
%%---------------------------------------------------------
|
||||
%% Ignore stuff
|
||||
%%---------------------------------------------------------
|
||||
%% "{WHITE}". %% whitespace
|
||||
%% "#.*". %% Ignore Macro stuff for now
|
||||
%% "{COMMENT}". %% Ignore Comments
|
||||
|
||||
%% C comments are /* ... */
|
||||
%% Our comments are (* ... *) {we have to quote ( and * yuck
|
||||
%% i.e. write \* and \( }
|
||||
%%
|
||||
|
||||
%% COMMENT "/\\*/*([^*/]|[^*]/|\\*[^/])*\\**\\*/". (tobbe)
|
||||
%% COMMENT "(\\*/*([^*)]|[^*])|\\*[^)])*\\**\\*)". (modified)
|
||||
%% COMMENT "\(\\*/*([^*\)]|[^*]\)|\\*[^\)])*\\**\\*\)". (quoted)
|
||||
|
||||
= : {token, {'=', YYline}}.
|
||||
\+ : {token, {'+', YYline}}.
|
||||
\- : {token, {'-', YYline}}.
|
||||
\; : {token, {';', YYline}}.
|
||||
} : {token, {'}', YYline}}.
|
||||
{ : {token, {'{', YYline}}.
|
||||
\[ : {token, {'[', YYline}}.
|
||||
\] : {token, {']', YYline}}.
|
||||
\( : {token, {'(', YYline}}.
|
||||
\) : {token, {')', YYline}}.
|
||||
\| : {token, {'|', YYline}}.
|
||||
\: : {token, {':', YYline}}.
|
||||
|
||||
(.|\n) : skip_token.
|
||||
|
||||
\.[\s\t\n] : {end_token,{'$end', YYline}}.
|
||||
|
||||
Erlang code.
|
||||
|
||||
string_gen([$\\|Cs]) ->
|
||||
string_escape(Cs);
|
||||
string_gen([C|Cs]) ->
|
||||
[C|string_gen(Cs)];
|
||||
string_gen([]) -> [].
|
||||
|
||||
string_escape([O1,O2,O3|S]) when
|
||||
O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
|
||||
[(O1*8 + O2)*8 + O3 - 73*$0|string_gen(S)];
|
||||
string_escape([$^,C|Cs]) ->
|
||||
[C band 31|string_gen(Cs)];
|
||||
string_escape([C|Cs]) when C >= 0, C =< $ ->
|
||||
string_gen(Cs);
|
||||
string_escape([C|Cs]) ->
|
||||
[escape_char(C)|string_gen(Cs)].
|
||||
|
||||
escape_char($n) -> $\n; %\n = LF
|
||||
escape_char($r) -> $\r; %\r = CR
|
||||
escape_char($t) -> $\t; %\t = TAB
|
||||
escape_char($v) -> $\v; %\v = VT
|
||||
escape_char($b) -> $\b; %\b = BS
|
||||
escape_char($f) -> $\f; %\f = FF
|
||||
escape_char($e) -> $\e; %\e = ESC
|
||||
escape_char($s) -> $ ; %\s = SPC
|
||||
escape_char($d) -> $\d; %\d = DEL
|
||||
escape_char(C) -> C.
|
||||
|
||||
remove_brackets([_,_|T]) ->
|
||||
[_,_|T1] = lists:reverse(T),
|
||||
lists:reverse(T1).
|
||||
|
||||
special("COMPILER", Line) -> {'COMPILER', Line};
|
||||
special("CHARACTERS", Line) -> {'CHARACTERS', Line};
|
||||
special("COMMENTS", Line) -> {'COMMENTS', Line};
|
||||
special("FROM", Line) -> {'FROM', Line};
|
||||
special("TO", Line) -> {'TO', Line};
|
||||
special("TOKENS", Line) -> {'TOKENS', Line};
|
||||
special("IGNORE", Line) -> {'IGNORE', Line};
|
||||
special("PRODUCTIONS", Line) -> {'PRODUCTIONS', Line};
|
||||
special("END", Line) -> {'END', Line};
|
||||
special("NESTED", Line) -> {'NESTED', Line};
|
||||
special("EOL", Line) -> {'EOL', Line};
|
||||
special("CHR", Line) -> {'CHR', Line};
|
||||
special("ANY", Line) -> {'ANY', Line};
|
||||
special(Other, Line) -> {var, Line, Other}.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
Nonterminals
|
||||
|
||||
production
|
||||
form lhs factor
|
||||
nested syntax char_prods charline char_rhs char_prim
|
||||
ignore moreignore expr term.
|
||||
|
||||
Terminals
|
||||
atom var string quote '|' '=' '}' '{' '(' ')' '[' ']'
|
||||
'COMPILER' 'CHARACTERS' 'COMMENTS' 'FROM' 'TO' 'TOKENS'
|
||||
'IGNORE' 'PRODUCTIONS' 'END' 'NESTED' 'EOL' 'CHR' 'ANY' integer comment
|
||||
'+' '-' ';'.
|
||||
|
||||
|
||||
Rootsymbol form.
|
||||
|
||||
form -> 'COMPILER' atom : {compiler, unwrap('$2')}.
|
||||
form -> 'CHARACTERS' char_prods : {characters, '$2'}.
|
||||
form -> 'COMMENTS' 'FROM' string
|
||||
'TO' string nested : {comments,unwrap('$3'),unwrap('$5'),
|
||||
'$6'}.
|
||||
form -> 'TOKENS' syntax : {tokens, '$2'}.
|
||||
form -> 'IGNORE' ignore : {ignore, '$2'}.
|
||||
form -> 'PRODUCTIONS' syntax : {syntax, '$2'}.
|
||||
form -> 'END' atom : {theend, '$2'}.
|
||||
form -> comment.
|
||||
|
||||
nested -> 'NESTED' : nested.
|
||||
nested -> 'EOL' : eol.
|
||||
nested -> '$empty' : not_nested.
|
||||
|
||||
%% Character syntax
|
||||
|
||||
char_prods -> charline ';' char_prods : ['$1'|'$3'].
|
||||
char_prods -> charline : ['$1'].
|
||||
|
||||
charline -> atom '=' char_rhs : {unwrap('$1'), '$3'}.
|
||||
|
||||
char_rhs -> char_prim '+' char_rhs : {plus, '$1', '$3'}.
|
||||
char_rhs -> char_prim '-' char_rhs : {minus, '$1', '$3'}.
|
||||
char_rhs -> char_prim : '$1'.
|
||||
|
||||
char_prim -> 'CHR' '(' integer ')' : {chr, unwrap('$3')}.
|
||||
char_prim -> string : {string, unwrap('$1')}.
|
||||
char_prim -> quote : {string, unwrap('$1')}.
|
||||
char_prim -> atom : {atom, unwrap('$1')}.
|
||||
char_prim -> 'ANY' : any.
|
||||
|
||||
ignore -> var moreignore : [unwrap('$1')|'$2'].
|
||||
|
||||
moreignore -> '+' ignore : '$2'.
|
||||
moreignore -> '$empty' : [].
|
||||
|
||||
%% The following deifinitions are taken from [WIR82]
|
||||
%% WIR82 Programming in Modular2
|
||||
%% Springer Verlag 1982
|
||||
|
||||
%% statement : A syntactic form
|
||||
%% expression : A list of alternatives
|
||||
%% term : A concatination of factors
|
||||
%% factor : A single syntactoc entity or a parenthesized expression
|
||||
|
||||
%% Construct
|
||||
%% =========
|
||||
%% [ A ] = zero or more A's
|
||||
%% { A } = any number of A's
|
||||
%% "A" = a string parse tree
|
||||
%% A | B = A or B parse tree
|
||||
%% A B = sequence of A followed by B
|
||||
%% identifier = a name
|
||||
|
||||
%% syntax = {production}
|
||||
%% production = id "=" expr ";"
|
||||
%% expr = term {"|" term}
|
||||
%% term = factor {factor}
|
||||
%% factor = id | string "{" expr "}
|
||||
|
||||
syntax -> production ';' syntax : ['$1'|'$3'].
|
||||
syntax -> production : ['$1'].
|
||||
|
||||
production -> lhs '=' expr : {prod, '$1', '$3'}.
|
||||
|
||||
lhs -> var : unwrap('$1').
|
||||
lhs -> atom : unwrap('$1').
|
||||
|
||||
expr -> term : '$1'.
|
||||
expr -> term '|' expr : {alt, '$1', '$3'}.
|
||||
|
||||
term -> factor : '$1'.
|
||||
term -> factor term : {seq, '$1', '$2'}.
|
||||
|
||||
factor -> atom : {nt, unwrap('$1')}.
|
||||
factor -> var : {ta, unwrap('$1')}.
|
||||
factor -> string : {ts, unwrap('$1')}.
|
||||
factor -> quote : {tq, unwrap('$1')}.
|
||||
factor -> '[' expr ']' : {one, '$2'}.
|
||||
factor -> '{' expr '}' : {star, '$2'}.
|
||||
factor -> '(' expr ')' : {bracket, '$2'}.
|
||||
|
||||
Erlang code.
|
||||
|
||||
unwrap({_,_,V}) -> V.
|
||||
|
||||
simplify({Tag,A,nil}) -> A;
|
||||
simplify(X) -> X.
|
||||
@@ -1,58 +0,0 @@
|
||||
-module(ecc_parse).
|
||||
|
||||
-doc([{author, 'Joe Armstrong'},
|
||||
{title, "Parser for the <b>ecc</b> language."},
|
||||
{keywords,[ecc,parser,yecc,leex]},
|
||||
{date, 891106}]).
|
||||
|
||||
-export([make/0, file/1]).
|
||||
|
||||
%% usage
|
||||
%% ecc_parse:file(File)
|
||||
%% Converts File.ebnf -> File.xbin
|
||||
%% ecc_parse:make()
|
||||
%% Makes the parser
|
||||
|
||||
make() ->
|
||||
%% The parser is made from
|
||||
%% ecc.yrl and ecc.xrl
|
||||
yecc:yecc("ecc", "ecc_yecc"),
|
||||
c:c(ecc_yecc),
|
||||
leex:gen(ecc, ecc_lex),
|
||||
c:c(ecc_lex).
|
||||
|
||||
file(F) ->
|
||||
io:format("Parsing ~s.ecc~n", [F]),
|
||||
{ok, Stream} = file:open(F ++ ".ecc", read),
|
||||
Parse = handle(Stream, 1, [], 0),
|
||||
file:close(Stream),
|
||||
Parse.
|
||||
|
||||
handle(Stream, LineNo, L, NErrors) ->
|
||||
handle1(io:requests(Stream, [{get_until,foo,ecc_lex,
|
||||
tokens,[LineNo]}]), Stream, L, NErrors).
|
||||
|
||||
handle1({ok, Toks, Next}, Stream, L, Nerrs) ->
|
||||
case ecc_yecc:parse(Toks) of
|
||||
{ok, Parse} ->
|
||||
handle(Stream, Next, [Parse|L], Nerrs);
|
||||
{error, {Line, Mod, What}} ->
|
||||
Str = apply(Mod, format_error, [What]),
|
||||
io:format("** ~w ~s~n", [Line, Str]),
|
||||
handle(Stream, Next, L, Nerrs+1);
|
||||
Other ->
|
||||
io:format("Bad_parse:~p\n", [Other]),
|
||||
handle(Stream, Next, L, Nerrs+1)
|
||||
end;
|
||||
handle1({eof, _}, Stream, L, 0) ->
|
||||
{ok, lists:reverse(L)};
|
||||
handle1({eof, _}, Stream, L, N) ->
|
||||
{error, N};
|
||||
handle1(What, Stream, L, Nerrs) ->
|
||||
io:format("Here:~p\n", [What]),
|
||||
handle(Stream, 1, L, Nerrs+1).
|
||||
|
||||
first([H]) -> [];
|
||||
first([H|T]) -> [H|first(T)];
|
||||
first([]) -> [].
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
-module(ermake).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Erlang make utility."},
|
||||
{keywords, [make]},
|
||||
{date,981103}]).
|
||||
|
||||
-export([all/0, target/1, file/1, file/2]).
|
||||
|
||||
-import(lists, [delete/2, filter/2, foldl/3, map/2, max/1, member/2, zf/2]).
|
||||
|
||||
%% all() -> Makes first target in EMakefile
|
||||
%% target(target::string()) -> Makes Target in EMakefile
|
||||
%% file(file()) -> Makes first target in File
|
||||
%% file(file(), target::string()) -> Makes Target in File
|
||||
|
||||
all() -> file("EMakefile").
|
||||
|
||||
target(T) -> file("EMakefile", T).
|
||||
|
||||
file(File) -> make(File, top).
|
||||
|
||||
file(File, Target) -> make(File, {target, Target}).
|
||||
|
||||
make(File, Target) ->
|
||||
Lines = ermake_parse:parse(File),
|
||||
Rules = filter(fun(X) -> element(1, X) == make end, Lines),
|
||||
Suffix = filter(fun(X) -> element(1, X) == suffix end, Lines),
|
||||
Rules1 = add_extra_rules(Rules, Suffix),
|
||||
case Target of
|
||||
top ->
|
||||
case hd(Rules) of
|
||||
{make, Ts, _, _} ->
|
||||
make_everything(Ts, Rules1);
|
||||
_ ->
|
||||
nothing_to_do
|
||||
end;
|
||||
{target, T} ->
|
||||
make_everything([T], Rules1)
|
||||
end.
|
||||
|
||||
add_extra_rules(Rules, Suffix) ->
|
||||
%% If a dependent is mentioned and
|
||||
%% there is no explicit rule for how to make the dependent then
|
||||
%% add an extra rule if possible
|
||||
Targets = [T || {make,Ts,_,_} <- Rules, T <- Ts],
|
||||
Dependents = [D || {make, _, Ds, _} <- Rules, D <- Ds],
|
||||
Missing = filter(fun(I) -> not member(I, Targets) end, Dependents),
|
||||
Missing1 = remove_duplicates(Missing),
|
||||
Extra = zf(fun(I) -> find_suffix_rule(I, Suffix) end, Missing1),
|
||||
Rules ++ Extra.
|
||||
|
||||
make_everything(Targets, Rules) ->
|
||||
Ps = [{T, D} || {make, Ts, Ds, _} <- Rules, T <- Ts, D <- Ds],
|
||||
%% trace all the rules we can reach from the root set
|
||||
L0 = transitive:closure(Targets, Ps),
|
||||
L = delete(true, L0),
|
||||
%% keep those rules that are mentioned in targets or destinations
|
||||
Ps1 = filter(fun({D,T}) ->
|
||||
member(D, L) or member(T, L)
|
||||
end, Ps),
|
||||
%% reverse the order to build the bottom up tree
|
||||
Ps2 = map(fun({I,J}) -> {J, I} end, Ps1),
|
||||
%% order the result
|
||||
case topological_sort:sort(Ps2) of
|
||||
{ok, Order0} ->
|
||||
Order = delete(true, Order0),
|
||||
%% Order is the absolute order to build things
|
||||
Cmds = map(fun(I) -> select_rule(I, Rules) end, Order),
|
||||
foldl(fun do_cmd/2, [], Cmds),
|
||||
true;
|
||||
{cycle, Cycle} ->
|
||||
exit({makefile,contains,cycle,Cycle})
|
||||
end.
|
||||
|
||||
%% find which rule is needed to build Target
|
||||
|
||||
select_rule(Target, Rules) ->
|
||||
Matches = [{make, Ts,Ds,Fun}|| {make,Ts,Ds,Fun} <- Rules,
|
||||
member(Target, Ts)],
|
||||
case length(Matches) of
|
||||
0 -> {file, Target};
|
||||
1 -> hd(Matches);
|
||||
_ -> exit({multiple,rules,to,make,Target})
|
||||
end.
|
||||
|
||||
%% do_cmd(cmd(), made()) -> make()'
|
||||
%% cmd() = {make, Targets, Dependents, Fun} | {file, Target}
|
||||
%% made() = [Target, time()].
|
||||
|
||||
do_cmd({make, Bins, Srcs, Fun}, Made) ->
|
||||
case target_time(Bins, Made) of
|
||||
none ->
|
||||
eval(Bins, Fun);
|
||||
{missing, M} ->
|
||||
eval(Bins, Fun);
|
||||
{max, TBin} ->
|
||||
case target_time(Srcs, Made) of
|
||||
{missing, M} ->
|
||||
exit({'I don\'t know how to make',M});
|
||||
{max, TSrc} when TSrc > TBin ->
|
||||
eval(Bins, Fun);
|
||||
{max, _} ->
|
||||
true;
|
||||
none ->
|
||||
exit({no,src,Srcs})
|
||||
end
|
||||
end,
|
||||
update_times(Srcs ++ Bins, this_time(), Made);
|
||||
do_cmd({file,H}, Made) ->
|
||||
update_times([H], this_time(), Made).
|
||||
|
||||
%% target_time(Targets, Made) -> {max, Time} | {missing,M}
|
||||
%% none
|
||||
%% if no targets found
|
||||
%% {missing, M}
|
||||
%% if target M is missing
|
||||
%% {max, Time}
|
||||
%% Time is the last modified time of all the targets
|
||||
%% the limes are derived from either the Made list
|
||||
%% or from the time stamp of the file.
|
||||
|
||||
target_time(Targets, Made) ->
|
||||
target_time(Targets, Made, []).
|
||||
|
||||
target_time([H|T], Made, Times) ->
|
||||
case make_time(H, Made) of
|
||||
{yes, Time} ->
|
||||
target_time(T, Made, [Time|Times]);
|
||||
no ->
|
||||
case is_file(H) of
|
||||
true ->
|
||||
target_time(T, Made, [last_modified(H)|Times]);
|
||||
false ->
|
||||
{missing, H}
|
||||
end
|
||||
end;
|
||||
target_time([], Made, []) ->
|
||||
none;
|
||||
target_time([], Made, Times) ->
|
||||
{max, max(Times)}.
|
||||
|
||||
make_time(X, [{X,Time}|_]) -> {yes, Time};
|
||||
make_time(X, [_|T]) -> make_time(X, T);
|
||||
make_time(X, []) -> no.
|
||||
|
||||
update_times([H|T], Now, Made) ->
|
||||
case make_time(H, Made) of
|
||||
{yes, _} -> update_times(T, Now, Made);
|
||||
no ->
|
||||
case is_file(H) of
|
||||
true ->
|
||||
update_times(T, Now, [{H, last_modified(H)}|Made]);
|
||||
false ->
|
||||
update_times(T, Now, [{H, Now}|Made])
|
||||
end
|
||||
end;
|
||||
update_times([], _, Made) ->
|
||||
Made.
|
||||
|
||||
%% see if a suffix rule can be applied to the file D
|
||||
|
||||
find_suffix_rule(D, Suffix) ->
|
||||
Ext = filename:extension(D),
|
||||
find_suffix_rule(Ext, D, Suffix).
|
||||
|
||||
find_suffix_rule(To, D, [{suffix, [From, To], Fun}|_]) ->
|
||||
Root = filename:rootname(D),
|
||||
Fun1 = expand_cmd(Fun, Root),
|
||||
{true, {make, [D], [Root ++ From], Fun1}};
|
||||
find_suffix_rule(To, D, [_|T]) ->
|
||||
find_suffix_rule(To, D, T);
|
||||
find_suffix_rule(_, _, []) ->
|
||||
false.
|
||||
|
||||
expand_cmd([$$,$>|T], Root) ->
|
||||
Root ++ expand_cmd(T, Root);
|
||||
expand_cmd([H|T], Root) ->
|
||||
[H|expand_cmd(T, Root)];
|
||||
expand_cmd([], _) ->
|
||||
[].
|
||||
|
||||
eval(_, []) ->
|
||||
true;
|
||||
eval(Target, Str) ->
|
||||
io:format("make ~p ->~n~s~n",[Target, Str]),
|
||||
case erl_scan:tokens([], "fun() -> " ++ Str ++ " end. ", 1) of
|
||||
{done, {ok, Toks, _},_} ->
|
||||
case erl_parse:parse_exprs(Toks) of
|
||||
{ok, [Parse]} ->
|
||||
%% io:format("Parse = ~p~n",[Parse]),
|
||||
Env0 = erl_eval:new_bindings(),
|
||||
Call = [{call,9999,Parse,[]}],
|
||||
case erl_eval:exprs(Call, Env0) of
|
||||
{value, Val, _} ->
|
||||
Val;
|
||||
O3 ->
|
||||
exit({eval,error,O3})
|
||||
end;
|
||||
O1 ->
|
||||
exit({parse,error,o1,O1})
|
||||
end;
|
||||
O2 ->
|
||||
exit({tokenisation,error,O2})
|
||||
end.
|
||||
|
||||
%% Stuff that should have been in the libraries (sigh :-)
|
||||
|
||||
last_modified(F) ->
|
||||
case file:file_info(F) of
|
||||
{ok, {_, _, _, _, Time, _, _}} ->
|
||||
Time;
|
||||
_ ->
|
||||
exit({last_modified, F})
|
||||
end.
|
||||
|
||||
is_file(File) ->
|
||||
case file:file_info(File) of
|
||||
{ok, _} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
remove_duplicates(L) ->
|
||||
foldl(fun(I, Acc) ->
|
||||
case member(I, Acc) of
|
||||
true -> Acc;
|
||||
false -> [I|Acc]
|
||||
end
|
||||
end, [], L).
|
||||
|
||||
this_time() ->
|
||||
{Y,M,D} = date(),
|
||||
{H,Min,S} = time(),
|
||||
{Y,M,D,H,Min,S}.
|
||||
@@ -1,246 +0,0 @@
|
||||
-module(ermake_line_reader).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Provide character level input for utilities such as make, lex, yacc etc. This module reads lines up to dot whitespace. Include files and named macros are expanded in place."},
|
||||
{keywords, [read,line,make,dot,whitespace,forms]},
|
||||
{date,981028}]).
|
||||
|
||||
%% This module provides a common *character level input*
|
||||
%% For Erlang look-alike utilities such as make, yecc, lex
|
||||
%% It provides
|
||||
%% 1) Multiple line input terminated by dot white space
|
||||
%% 2) Variables VAR = Val, or VAR += Val
|
||||
%% 3) Include files include("File")
|
||||
%% 4) comment stripping %... are removed
|
||||
|
||||
-export([test/1, read_file/1, read_file/2]).
|
||||
|
||||
-import(lists, [keyreplace/4, keysearch/3, member/2, reverse/1, reverse/2]).
|
||||
|
||||
test(1) -> read_file("EMakefile");
|
||||
test(2) -> read_file("test1").
|
||||
|
||||
read_file(File) ->
|
||||
read_file(File, []).
|
||||
|
||||
read_file(File, Macros) ->
|
||||
{Macros1, Lines} = read_lines(File, Macros, [File]),
|
||||
%% io:format("Macros were:~p~n",[Macros1]),
|
||||
trim(Lines).
|
||||
|
||||
trim([{{File,Line},Str}|T]) ->
|
||||
Leading = count_leading_nls(Str, Line),
|
||||
case trim_line(Str) of
|
||||
[] -> trim(T);
|
||||
Str1 -> [{File,Leading,Str1}|trim(T)]
|
||||
end;
|
||||
trim([]) -> [].
|
||||
|
||||
trim_line(Str) ->
|
||||
Str1 = skip_white(Str),
|
||||
trim_end_of_line(Str1).
|
||||
|
||||
trim_end_of_line(Str1) ->
|
||||
case reverse(Str1) of
|
||||
[X,$.|Tmp] ->
|
||||
reverse(Tmp);
|
||||
[] ->
|
||||
[];
|
||||
Other ->
|
||||
exit({oops,Other})
|
||||
end.
|
||||
|
||||
read_lines(File, Macros0, Stack) ->
|
||||
case file:read_file(File) of
|
||||
{ok, Bin} ->
|
||||
Lines = gather_lines(binary_to_list(Bin), File, 1, []),
|
||||
%% io:format("Lines=~p~n",[Lines]),
|
||||
expand(Lines, Macros0, Stack, []);
|
||||
_ ->
|
||||
exit({cannot,read,file,File})
|
||||
end.
|
||||
|
||||
expand([{Where, H}|T], Macros, Stack, L) ->
|
||||
%% first expand any macros
|
||||
H1 = expand_macro(H, Macros, Where),
|
||||
%% now add any macro definitions
|
||||
case is_macro_defn(H1) of
|
||||
{new, Var, Val} ->
|
||||
case keysearch(Var,1,Macros) of
|
||||
{value,{_,Val}} ->
|
||||
%% same value no problem
|
||||
expand(T, Macros, Stack, L);
|
||||
{value,{_,Replacement}} ->
|
||||
%% some other value
|
||||
exit({error, Where, cannot,redefine,macro,
|
||||
Var,was,Replacement,is,Val});
|
||||
false ->
|
||||
%% new definition
|
||||
expand(T, [{Var,Val}|Macros], Stack, L)
|
||||
end;
|
||||
{plus, Var, Val} ->
|
||||
case keysearch(Var,1,Macros) of
|
||||
{value,{_,Old}} ->
|
||||
%% some other value
|
||||
Macros1 = keyreplace(Var,1,Macros,{Var,Old++Val}),
|
||||
expand(T, Macros1, Stack, L);
|
||||
false ->
|
||||
exit({error, Where, no,previous,defn,for,Var})
|
||||
end;
|
||||
no ->
|
||||
case is_include(H1, Where) of
|
||||
{yes, File} ->
|
||||
case member(File, Stack) of
|
||||
true ->
|
||||
exit({error, Where, recursive_include, File});
|
||||
false ->
|
||||
{Macros1, Lines1} = read_lines(File,Macros,Stack),
|
||||
expand(T, Macros1, Stack, reverse(Lines1, L))
|
||||
end;
|
||||
no ->
|
||||
expand(T, Macros, Stack, [{Where, H1}|L])
|
||||
end
|
||||
end;
|
||||
expand([], Macros, Stack, L) ->
|
||||
{Macros, reverse(L)}.
|
||||
|
||||
expand_macro([$$,$(|T], Macros, Where) ->
|
||||
case is_var(T) of
|
||||
{yes, Var, [$)|T1]} ->
|
||||
case keysearch(Var,1,Macros) of
|
||||
{value,{_,Replacement}} ->
|
||||
Replacement ++ expand_macro(T1, Macros, Where);
|
||||
false ->
|
||||
exit({error,Where,undefined,macro,Var})
|
||||
end;
|
||||
no ->
|
||||
[$$,$(|expand_macro(T, Macros, Where)]
|
||||
end;
|
||||
expand_macro([H|T], Macros, Where) ->
|
||||
[H|expand_macro(T, Macros, Where)];
|
||||
expand_macro([], Macros, _) ->
|
||||
[].
|
||||
|
||||
is_include(Line, Where) ->
|
||||
case skip_white(Line) of
|
||||
[$i,$n,$c,$l,$u,$d,$e,$(,$"|T] ->
|
||||
{File, T1} = get_quoted([$"|T], Where),
|
||||
case skip_white(T1) of
|
||||
[$)|_] ->
|
||||
{yes, File};
|
||||
_ ->
|
||||
exit({Where,bad,include,syntax})
|
||||
end;
|
||||
_ ->
|
||||
no
|
||||
end.
|
||||
|
||||
is_macro_defn(Line) ->
|
||||
Str1 = skip_white(Line),
|
||||
case is_var(Str1) of
|
||||
{yes, Var, Str2} ->
|
||||
case skip_white(Str2) of
|
||||
[$=|T] ->
|
||||
{new, Var, trim_end_of_line(T)};
|
||||
[$+,$=|T] ->
|
||||
{plus, Var, trim_end_of_line(T)};
|
||||
_ ->
|
||||
no
|
||||
end;
|
||||
no ->
|
||||
no
|
||||
end.
|
||||
|
||||
is_var([H|T]) when $A =< H, H =< $Z ->
|
||||
collect_var(T, [H]);
|
||||
is_var(_) ->
|
||||
no.
|
||||
|
||||
collect_var([H|T], L) when $A =< H, H =< $Z ->
|
||||
collect_var(T, [H|L]);
|
||||
collect_var([H|T], L) when $1 =< H, H =< $9 ->
|
||||
collect_var(T, [H|L]);
|
||||
collect_var([H|T], L) when $a =< H, H =< $z ->
|
||||
collect_var(T, [H|L]);
|
||||
collect_var(X, L) ->
|
||||
{yes, reverse(L), X}.
|
||||
|
||||
skip_white([$ |T]) -> skip_white(T);
|
||||
skip_white([$\n|T]) -> skip_white(T);
|
||||
skip_white([$\t|T]) -> skip_white(T);
|
||||
skip_white(T) -> T.
|
||||
|
||||
gather_lines([], File, N, L) ->
|
||||
reverse(L);
|
||||
gather_lines(Str, File, N, L) ->
|
||||
{Line, Str1} = get_line(Str, {File, N}, []),
|
||||
Width = count_nls(Line, 0),
|
||||
gather_lines(Str1, File, N + Width, [{{File,N},Line}|L]).
|
||||
|
||||
count_nls([$\n|T], N) -> count_nls(T, N+1);
|
||||
count_nls([_|T], N) -> count_nls(T, N);
|
||||
count_nls([], N) -> N.
|
||||
|
||||
count_leading_nls([$\n|T], N) -> count_leading_nls(T, N+1);
|
||||
count_leading_nls(_, N) -> N.
|
||||
|
||||
%% get_line collects a line up to . <white>
|
||||
|
||||
get_line([$.,X|T], Where, L) ->
|
||||
case X of
|
||||
$\n ->
|
||||
{reverse(L, [$.,$\n]), T};
|
||||
$ ->
|
||||
{reverse(L, [". "]), T};
|
||||
$\t ->
|
||||
{reverse(L, [$.,$\t]), T};
|
||||
_ ->
|
||||
get_line(T, Where, [X,$.|L])
|
||||
end;
|
||||
get_line([$"|T], Where, L) ->
|
||||
{Str, T1} = get_quoted([$"|T], Where),
|
||||
get_line(T1, Where, [$"|reverse(Str, [$"|L])]);
|
||||
get_line([$'|T], Where, L) ->
|
||||
{Str, T1} = get_quoted([$'|T], Where),
|
||||
get_line(T1, Where,[$'|reverse(Str, [$'|L])]);
|
||||
get_line([$%|T], Where, L) ->
|
||||
%% remove the comment
|
||||
T1 = skip_to_eol(T),
|
||||
get_line(T1, Where, L);
|
||||
get_line([H|T], Where, L) ->
|
||||
get_line(T, Where, [H|L]);
|
||||
get_line([], Where, L) ->
|
||||
{reverse(L), []}.
|
||||
|
||||
skip_to_eol([$\n|T]) -> [$\n|T];
|
||||
skip_to_eol([_|T]) -> skip_to_eol(T);
|
||||
skip_to_eol([]) -> [].
|
||||
|
||||
|
||||
%% get_quoted(string(), {file(),line()}) -> {quoted(), rest()}
|
||||
%% The " ' is not included
|
||||
|
||||
get_quoted([End|T], Where) ->
|
||||
get_quoted(T, Where, End, []).
|
||||
|
||||
get_quoted([End|T], Where, End, Acc) ->
|
||||
{reverse(Acc), T};
|
||||
get_quoted([$\\,C|T], Where, End, Acc) ->
|
||||
get_quoted(T, Where, End, [quoted(C)|Acc]);
|
||||
get_quoted([$\n|_], {File,Line}, _, _) ->
|
||||
exit({error, file, File, line, Line,
|
||||
"newline not allowed in string"});
|
||||
get_quoted([H|T], Where, End, Acc) ->
|
||||
get_quoted(T, Where, End, [H|Acc]);
|
||||
get_quoted([], {File,Line}, _, _) ->
|
||||
exit({error, file, File, line, Line,
|
||||
"end of line not allowed in string"}).
|
||||
|
||||
%% Quoted characters
|
||||
|
||||
quoted($n) -> $\n;
|
||||
quoted($t) -> $\t;
|
||||
quoted($r) -> $\r;
|
||||
quoted($b) -> $\b;
|
||||
quoted($v) -> $\v;
|
||||
quoted(C) -> C.
|
||||
@@ -1,73 +0,0 @@
|
||||
-module(ermake_parse).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Parser used by ermake."},
|
||||
{keywords, [parser,make]},
|
||||
{date,981029}]).
|
||||
|
||||
-export([parse/1]).
|
||||
|
||||
-import(lists, [reverse/1, prefix/2, map/2]).
|
||||
|
||||
parse(File) ->
|
||||
Dir = filename:dirname(code:which(?MODULE)),
|
||||
Lines = ermake_line_reader:read_file(File, [{"MAKEDIR", Dir}]),
|
||||
map(fun parse_line/1, Lines).
|
||||
|
||||
parse_line({File,Line,Str}) ->
|
||||
parse_str(Str).
|
||||
|
||||
parse_str([$S,$u,$f,$f,$i,$x,$ |T]) ->
|
||||
%% io:format("Suffix:~s~n",[T]),
|
||||
case split("->", T) of
|
||||
{yes, Pre, Fun} ->
|
||||
Tmp = string:tokens(Pre,". "),
|
||||
Tmp1 = map(fun(I) -> [$.|I] end, Tmp),
|
||||
{suffix, Tmp1, Fun};
|
||||
no ->
|
||||
exit({'No -> in suffix rule', T})
|
||||
end;
|
||||
parse_str(Str) ->
|
||||
case split("when", Str) of
|
||||
{yes, As, BsF} ->
|
||||
case split("->", BsF) of
|
||||
%% As when Bs -> F
|
||||
{yes, Bs, F} ->
|
||||
{make, parse_files(As), parse_files(Bs),
|
||||
parse_fun(F)};
|
||||
no ->
|
||||
%% As when Bs.
|
||||
{make, parse_files(As), parse_files(BsF), []}
|
||||
end;
|
||||
no ->
|
||||
%% A -> F
|
||||
case split("->", Str) of
|
||||
no ->
|
||||
exit({'No "when" or "->" in rule', Str});
|
||||
{yes, As, F} ->
|
||||
{make, parse_files(As), [true], parse_fun(F)}
|
||||
end
|
||||
end.
|
||||
|
||||
%% split(Prefix, String) -> {yes, Before, After} | no
|
||||
%% splits String at Prefix
|
||||
|
||||
split(Prefix, L) -> split(Prefix, L, []).
|
||||
|
||||
split(_, [], L) ->
|
||||
no;
|
||||
split(Prefix, L, L1) ->
|
||||
case prefix(Prefix, L) of
|
||||
true ->
|
||||
{yes, reverse(L1), string:substr(L, length(Prefix)+1)};
|
||||
false ->
|
||||
split(Prefix, tl(L), [hd(L)|L1])
|
||||
end.
|
||||
|
||||
parse_files(Str) ->
|
||||
Files = string:tokens(Str, [$ ,$,,$\n,$\t]).
|
||||
|
||||
parse_fun([$\n|F]) -> F;
|
||||
parse_fun(F) -> F.
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
-module(error_handler).
|
||||
|
||||
-doc([{author,joe},
|
||||
{title,"Special version of error handler used by sos.erl"},
|
||||
{date,981012}]).
|
||||
|
||||
-export([undefined_function/3,undefined_global_name/2]).
|
||||
|
||||
undefined_function(sos, F, A) ->
|
||||
erlang:display({error_handler,undefined_function,
|
||||
sos,F,A}),
|
||||
exit(oops);
|
||||
undefined_function(M, F, A) ->
|
||||
case sos:load_module(M) of
|
||||
{ok, M} ->
|
||||
case erlang:function_exported(M,F,length(A)) of
|
||||
true ->
|
||||
apply(M, F, A);
|
||||
false ->
|
||||
sos:stop_system({undef,{M,F,A}})
|
||||
end;
|
||||
{ok, Other} ->
|
||||
sos:stop_system({undef,{M,F,A}});
|
||||
already_loaded ->
|
||||
sos:stop_system({undef,{M,F,A}});
|
||||
{error, What} ->
|
||||
sos:stop_system({load,error,What})
|
||||
end.
|
||||
undefined_global_name(Name, Message) ->
|
||||
exit({badarg,{Name,Message}}).
|
||||
@@ -1,170 +0,0 @@
|
||||
-module(find).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Find all files. Find all out of date files.
|
||||
<p>A find utility which finds all files (and directories)
|
||||
relative to a given root directory"},
|
||||
{keywords, [find,make]},
|
||||
{api,["find:files(\".\", \"*.erl\", false)</b> finds all
|
||||
entries in the current directory.
|
||||
Recursive scan of sub-directories is also allowed.",
|
||||
"find:out_of_date(\".\",\".erl\",\".jam\")</b> finds all out of date
|
||||
Erlang files in the current directory"]},
|
||||
{date,970203}]).
|
||||
|
||||
-export([files/3, out_of_date/3]).
|
||||
|
||||
-import(lists, [suffix/2, sublist/3, map/2, filter/2]).
|
||||
|
||||
|
||||
%% files(Dir, ReExpr, Recursive) -> [File]
|
||||
%% Find regular files starting from Dir
|
||||
%% Which match ReExpr
|
||||
%% If Recursive is true do recursivly on all sub-directories
|
||||
%% Example find(".", "*.erl", false) will find all erlang files in the
|
||||
%% Current directory
|
||||
%%
|
||||
%% out_of_date(Dir, SrcExt, ObjExt) find all "out of date files" in
|
||||
%% Dir.
|
||||
%% Example:
|
||||
%% out_of_date(".", ".erl", ".jam")
|
||||
%% Finds all out of date files in the current directory
|
||||
|
||||
files(Dir, Re, Flag) ->
|
||||
Re1 = string:re_sh_to_awk(Re),
|
||||
find_files(Dir, Re1, Flag, []).
|
||||
|
||||
%% +type find_files(dirname(), Regexp, bool(), [filename()]) -> [filename()]
|
||||
%% when Regexp = string().
|
||||
|
||||
find_files(Dir, Re, Flag, L) ->
|
||||
case file:list_dir(Dir) of
|
||||
{ok, Files} -> find_files(Files, Dir, Re, Flag, L);
|
||||
{error, _} -> L
|
||||
end.
|
||||
|
||||
%% +type find_files([filename()], dirname(), Regexp, bool(), [filename()]) ->
|
||||
%% [filename()] when Regexp = string().
|
||||
|
||||
find_files([File|T], Dir, Re, Recursive, L) ->
|
||||
FullName = Dir ++ [$/|File],
|
||||
case file_type(FullName) of
|
||||
regular ->
|
||||
case string:re_match(FullName, Re) of
|
||||
{match, _, _} ->
|
||||
find_files(T, Dir, Re, Recursive, [FullName|L]);
|
||||
_ ->
|
||||
find_files(T, Dir, Re, Recursive, L)
|
||||
end;
|
||||
directory ->
|
||||
case Recursive of
|
||||
true ->
|
||||
L1 = find_files(FullName, Re, Recursive, L),
|
||||
find_files(T, Dir, Re, Recursive, L1);
|
||||
false ->
|
||||
find_files(T, Dir, Re, Recursive, L)
|
||||
end;
|
||||
error ->
|
||||
find_files(T, Dir, Re, Recursive, L)
|
||||
end;
|
||||
find_files([], _, _, _, L) ->
|
||||
L.
|
||||
|
||||
%% +type file_type(string()) -> regular | directory | error.
|
||||
|
||||
file_type(File) ->
|
||||
case file:file_info(File) of
|
||||
{ok, Facts} ->
|
||||
case element(2, Facts) of
|
||||
regular -> regular;
|
||||
directory -> directory;
|
||||
_ -> error
|
||||
end;
|
||||
_ ->
|
||||
error
|
||||
end.
|
||||
|
||||
|
||||
%%______________________________________________________________________
|
||||
%% outofdate(Dir, InExtension, OutExtension)
|
||||
%% scans Dir for all files with the extension "InExtension"
|
||||
%% If a file with this extension is found then "OutExtension" is checked
|
||||
%%
|
||||
%% returns a list of files in <Dir> where *.OutExtension is
|
||||
%% "out of date" with respect to *.InExtension
|
||||
%% in the sence of "make"
|
||||
|
||||
out_of_date(Dir, In, Out) ->
|
||||
case file:list_dir(Dir) of
|
||||
{ok, Files0} ->
|
||||
Files1 = filter(fun(F) ->
|
||||
suffix(In, F)
|
||||
end, Files0),
|
||||
Files2 = map(fun(F) ->
|
||||
sublist(F, 1,
|
||||
length(F)-length(In))
|
||||
end, Files1),
|
||||
filter(fun(F) -> update(F, In, Out) end,Files2);
|
||||
_ ->
|
||||
[]
|
||||
end.
|
||||
|
||||
%% +type update(string(), string(), string()) -> bool().
|
||||
|
||||
update(File, In, Out) ->
|
||||
InFile = File ++ In,
|
||||
OutFile = File ++ Out,
|
||||
case is_file(OutFile) of
|
||||
true ->
|
||||
case writeable(OutFile) of
|
||||
true ->
|
||||
outofdate(InFile, OutFile);
|
||||
false ->
|
||||
%% can't write so we can't update
|
||||
false
|
||||
end;
|
||||
false ->
|
||||
%% doesn't exist
|
||||
true
|
||||
end.
|
||||
|
||||
%% +type is_file(string()) -> bool().
|
||||
|
||||
is_file(File) ->
|
||||
case file:file_info(File) of
|
||||
{ok, _} ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
%% +type outofdate(string(), string()) -> bool().
|
||||
|
||||
outofdate(In, Out) ->
|
||||
case {last_modified(In), last_modified(Out)} of
|
||||
{T1, T2} when T1 > T2 ->
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
%% +type last_modified(string()) -> {int(), int(),int(), int(),int(), int()}
|
||||
%% | 'EXIT'({last_modified, string()}).
|
||||
|
||||
last_modified(F) ->
|
||||
case file:file_info(F) of
|
||||
{ok, {_, _, _, _, Time, _, _}} ->
|
||||
Time;
|
||||
_ ->
|
||||
exit({last_modified, F})
|
||||
end.
|
||||
|
||||
%% +type writeable(string()) -> bool().
|
||||
|
||||
writeable(F) ->
|
||||
case file:file_info(F) of
|
||||
{ok, {_,_,read_write,_,_,_,_}} -> true;
|
||||
{ok, {_,_,write ,_,_,_,_}} -> true;
|
||||
_ -> false
|
||||
end.
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
-module(ftp_client).
|
||||
|
||||
-doc([{author, joe},
|
||||
{title, "FTP client in pure Erlang -- i.e. an FTP client as it might
|
||||
have been written, i.e. not according to RFC 959"},
|
||||
{keywords,[ftp, client]},
|
||||
{date, 981014}]).
|
||||
|
||||
-export([connect/3, pwd/1, cd/2, ls/1, put/2, get/2, lcd/1, lpwd/0, lls/0,
|
||||
quit/1]).
|
||||
|
||||
connect(Host, User, Password) ->
|
||||
{ftp_server, Host} ! {connect,self(),User,Password},
|
||||
receive
|
||||
{ftp_server, Reply} -> Reply;
|
||||
Other -> Other
|
||||
after 10000 ->
|
||||
timeout
|
||||
end.
|
||||
|
||||
%S tag1
|
||||
pwd(Handle) -> remote(Handle, pwd).
|
||||
cd(Handle, Dir) -> remote(Handle, {cd, Dir}).
|
||||
ls(Handle) -> remote(Handle, ls).
|
||||
get(Handle, File) -> remote(Handle, {get, File}).
|
||||
quit(Handle) -> remote(Handle, quit).
|
||||
%E tag1
|
||||
|
||||
%S tag2
|
||||
lcd(Dir) -> file:set_cwd(Dir), lpwd().
|
||||
lpwd() -> cwd().
|
||||
lls() -> element(2, file:list_dir(cwd())).
|
||||
%E tag2
|
||||
|
||||
cwd() -> element(2, file:get_cwd()).
|
||||
|
||||
remote(Handle, Op) ->
|
||||
Handle ! {self(), Op},
|
||||
receive
|
||||
{ftp_server, Any} ->
|
||||
Any
|
||||
after 1000 ->
|
||||
timeout
|
||||
end.
|
||||
|
||||
put(Handle, File) ->
|
||||
case file:read_file(File) of
|
||||
{ok, Contents} ->
|
||||
remote(Handle, {put, File, Contents});
|
||||
Other ->
|
||||
Other
|
||||
end.
|
||||
@@ -1,123 +0,0 @@
|
||||
-module(ftp_server).
|
||||
|
||||
%% Look in ~tony/erlang/ftpd/ftpd.erl
|
||||
%% For filename stuff
|
||||
|
||||
-doc([{author, joe},
|
||||
{title, "FTP server in pure Erlang -- i.e. an FTP server as it
|
||||
might have been written, i.e. not according to RFC 959"},
|
||||
{keywords,[ftp, server]},
|
||||
{date, 981014}]).
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-export([start/0, internal/0, handler/1]).
|
||||
-import(lists, [member/2, reverse/1]).
|
||||
|
||||
start() ->
|
||||
case (catch register(ftp_server,
|
||||
spawn(?MODULE, internal, []))) of
|
||||
{'EXIT', _} ->
|
||||
already_started;
|
||||
Pid ->
|
||||
ok
|
||||
end.
|
||||
|
||||
internal() ->
|
||||
case file:consult("users") of
|
||||
{ok, Users} ->
|
||||
process_flag(trap_exit, true),
|
||||
loop(Users, 0);
|
||||
_ ->
|
||||
exit(no_users_allowed)
|
||||
end.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
loop(Users, N) ->
|
||||
receive
|
||||
{connect, Pid, User, Password} ->
|
||||
io:format("connection request from:~p ~p ~p~n",
|
||||
[Pid, User, Password]),
|
||||
case member({User, Password}, Users) of
|
||||
true ->
|
||||
Max = max_connections(),
|
||||
if
|
||||
N > Max ->
|
||||
Pid ! {ftp_server,
|
||||
{error, too_many_connections}},
|
||||
loop(Users, N);
|
||||
true ->
|
||||
New = spawn_link(?MODULE, handler, [Pid]),
|
||||
Pid ! {ftp_server, {ok, New}},
|
||||
loop(Users, N + 1)
|
||||
end;
|
||||
false ->
|
||||
Pid ! {ftp_server, {error, rejected}},
|
||||
loop(Users, N)
|
||||
end;
|
||||
{'EXIT', Pid} ->
|
||||
io:format("Handler ~p died~n", [Pid]),
|
||||
loop(Users, lists:max(N-1, 0));
|
||||
Any ->
|
||||
io:format("received:~p~n",[Any]),
|
||||
loop(Users, N)
|
||||
end.
|
||||
|
||||
handler(Pid) ->
|
||||
receive
|
||||
{Pid, quit} ->
|
||||
Pid ! {ftp_server, ok};
|
||||
{Pid, Op} ->
|
||||
io:format("got:~p ~p~n",[Pid, Op]),
|
||||
Pid ! {ftp_server, do_op(Op)},
|
||||
handler(Pid)
|
||||
end.
|
||||
|
||||
do_op({cd, Dir}) -> file:set_cwd(Dir), cwd();
|
||||
do_op(ls) -> element(2, file:list_dir(cwd()));
|
||||
do_op(pwd) -> cwd();
|
||||
do_op({get_file, File}) -> file:read_file(File).
|
||||
|
||||
max_connections() -> 10.
|
||||
|
||||
cwd() -> element(2, file:get_cwd()).
|
||||
|
||||
%% This was taken from Tony
|
||||
|
||||
%%
|
||||
%% Compose file/directory names
|
||||
%%
|
||||
rel_name(Name, Wd) ->
|
||||
case filename:pathtype(Name) of
|
||||
relative ->
|
||||
rel_path(filename:join(Wd, Name));
|
||||
absolute ->
|
||||
rel_path(Name);
|
||||
volumerelative ->
|
||||
rel_path(filename:join(Wd,Name))
|
||||
end.
|
||||
%%
|
||||
%% We sometime need a simulated root, then call abs_name
|
||||
%%
|
||||
abs_name(Name) ->
|
||||
filename:join("/", Name).
|
||||
|
||||
%%
|
||||
%% rel_path returns a relative path i.e remove
|
||||
%% and root or volume relative start components
|
||||
%%
|
||||
rel_path(Path) ->
|
||||
rel_path(filename:split(Path),[]).
|
||||
|
||||
%% remove absolute or volume relative stuff
|
||||
rel_path([Root|Path], RP) ->
|
||||
case filename:pathtype(Root) of
|
||||
relative -> rpath(Path, [Root|RP]);
|
||||
_ -> rpath(Path, RP)
|
||||
end.
|
||||
|
||||
rpath([".."|P], [_|RP]) -> rpath(P, RP);
|
||||
rpath(["."|P], RP) -> rpath(P, RP);
|
||||
rpath([F|P], RP) -> rpath(P, [F|RP]);
|
||||
rpath([],[]) -> "";
|
||||
rpath([], RP) -> filename:join(reverse(RP)).
|
||||
@@ -1,591 +0,0 @@
|
||||
%% THIS IS A PRE-RELEASE OF LEEX - RELEASED ONLY BECAUSE MANY PEOPLE
|
||||
%% WANTED IT - THE OFFICIAL RELEASE WILL PROVIDE A DIFFERENT INCOMPATIBLE
|
||||
%% AND BETTER INTERFACE - BE WARNED
|
||||
%% PLEASE REPORT ALL BUGS TO THE AUTHOR.
|
||||
|
||||
%% Copyright (C) 1996, Ellemtel Telecommunications Systems Laboratories
|
||||
%% File : leex.erl
|
||||
%% Author : Robert Virding (rv@cslab.ericsson.se)
|
||||
%% Purpose : A Lexical Analyser Generator for Erlang.
|
||||
|
||||
%% Most of the algorithms used here are taken pretty much as
|
||||
%% described in the "Dragon Book" by Aho, Sethi and Ullman. Some
|
||||
%% completing details were taken from "Compiler Design in C" by
|
||||
%% Hollub.
|
||||
|
||||
-module(leex).
|
||||
|
||||
-doc([{author,'Robert Virding'},
|
||||
{title,"A Lexical Analyser Generator for Erlang"},
|
||||
{keywords, [lex]},
|
||||
{date,981012}]).
|
||||
|
||||
-copyright('Copyright (c) 1996 Ericsson Telecommunications AB').
|
||||
|
||||
-author('rv@cslab.ericsson.se').
|
||||
|
||||
-export([gen/2,format_error/1]).
|
||||
|
||||
-import(lists, [member/2,reverse/1,seq/2,keymember/3,keysearch/3,keysort/2,
|
||||
foreach/2]).
|
||||
-import(ordsets, [is_element/2,add_element/2,union/2,subtract/2]).
|
||||
|
||||
%%-compile([export_all]).
|
||||
|
||||
-record(nfa_state, {no,edges=[],accept=noaccept}).
|
||||
-record(dfa_state, {no,nfa=[],trans=[],accept=noaccept}).
|
||||
|
||||
gen(In, Out) ->
|
||||
InFile = lists:concat([In,".xrl"]),
|
||||
OutFile = lists:concat([Out,".erl"]),
|
||||
case parse_file(InFile) of
|
||||
{ok,REAs,Actions,Code} ->
|
||||
%% io:fwrite("REAs = ~p\n", [REAs]),
|
||||
%% io:fwrite("Actions = ~p\n", [Actions]),
|
||||
{NFA,NF} = build_combined_nfa(REAs),
|
||||
io:fwrite("NFA contains ~w states, ", [size(NFA)]),
|
||||
%% io:fwrite("NFA = ~p~n ", [NFA]),
|
||||
{DFA0,DF0} = build_dfa(NFA, NF),
|
||||
io:fwrite("DFA contains ~w states, ", [length(DFA0)]),
|
||||
%% io:fwrite("DFA = ~p~n ", [DFA0]),
|
||||
{DFA,DF} = minimise_dfa(DFA0, DF0),
|
||||
io:fwrite("minimised to ~w states.~n", [length(DFA)]),
|
||||
out_file(OutFile, Out, DFA, DF, Actions, Code);
|
||||
{error,Error} ->
|
||||
io:put_chars([$\n,gcc_error(InFile, Error),$\n]),
|
||||
error
|
||||
end.
|
||||
|
||||
format_error({open,F}) -> ["error opening ",io_lib:write_string(F)];
|
||||
format_error(missing_rules) -> "missing rules";
|
||||
format_error(bad_rule) -> "bad rule";
|
||||
format_error({regexp,E}) -> ["bad regexp `",regexp:format_error(E),"'"];
|
||||
format_error({after_regexp,S}) ->
|
||||
["bad code after regexp ",io_lib:write_string(S)].
|
||||
|
||||
gcc_error(File, {Line,Mod,Error}) ->
|
||||
io_lib:format("~s:~w: ~s", [File,Line,apply(Mod, format_error, [Error])]);
|
||||
gcc_error(File, {Mod,Error}) ->
|
||||
io_lib:format("~s: ~s", [File,apply(Mod, format_error, [Error])]).
|
||||
|
||||
%% parse_file(InFile) -> {[REA],[Action],Code} | {error,Error}
|
||||
%% when
|
||||
%% REA = {RegExp,ActionNo};
|
||||
%% Action = {ActionNo,ActionString};
|
||||
%% Code = [char()].
|
||||
%%
|
||||
%% Read and parse the file InFile.
|
||||
%% After each section of the file has been parsed we directly call the
|
||||
%% next section. This is done when we detect a line we don't recognise
|
||||
%% in the current section. The file format is very simple and Erlang
|
||||
%% token based, we allow empty lines and Erlang style comments.
|
||||
|
||||
parse_file(InFile) ->
|
||||
case file:open(InFile, read) of
|
||||
{ok,Ifile} ->
|
||||
io:fwrite("Parsing file ~s, ", [InFile]),
|
||||
case parse_head(Ifile) of
|
||||
{ok,REAs,Actions,Code} ->
|
||||
io:fwrite("contained ~w rules.~n", [length(REAs)]),
|
||||
file:close(Ifile),
|
||||
{ok,REAs,Actions,Code};
|
||||
Error ->
|
||||
file:close(Ifile),
|
||||
Error
|
||||
end;
|
||||
{error,R} ->
|
||||
{error,{leex,{open,InFile}}}
|
||||
end.
|
||||
|
||||
%% parse_head(File)
|
||||
%% Parse the head of the file.
|
||||
|
||||
parse_head(Ifile) ->
|
||||
parse_defs(Ifile, nextline(Ifile, 0)).
|
||||
|
||||
%% parse_defs(File, Line)
|
||||
%% Parse the macro definition section of a file. Allow no definitions.
|
||||
|
||||
parse_defs(Ifile, {ok,[$D,$e,$f,$i,$n,$i,$t,$i,$o,$n,$s,$.|_Rest],L}) ->
|
||||
parse_defs(Ifile, nextline(Ifile, L), []);
|
||||
parse_defs(Ifile, Line) ->
|
||||
parse_rules(Ifile, Line, []).
|
||||
|
||||
parse_defs(Ifile, {ok,Chars,L}, Ms) ->
|
||||
case string:tokens(Chars, " \t\n") of
|
||||
[Name,"=",Def] ->
|
||||
parse_defs(Ifile, nextline(Ifile, L), [{Name,Def}|Ms]);
|
||||
Other ->
|
||||
parse_rules(Ifile, {ok,Chars,L}, Ms)
|
||||
end;
|
||||
parse_defs(Ifile, Line, Ms) ->
|
||||
parse_rules(Ifile, Line, Ms).
|
||||
|
||||
%% parse_rules(File, Line, Macros)
|
||||
%% Parse the RE rules section of the file. This must exist.
|
||||
|
||||
parse_rules(Ifile, {ok,[$R,$u,$l,$e,$s,$.|_Rest],L}, Ms) ->
|
||||
parse_rules(Ifile, nextline(Ifile, L), Ms, [], [], 0);
|
||||
parse_rules(Ifile, {ok,Other,L}, Ms) ->
|
||||
{error,{L,leex,missing_rules}};
|
||||
parse_rules(Ifile, {eof,L}, Ms) ->
|
||||
{error,{L,leex,missing_rules}}.
|
||||
|
||||
collect_rule(Ifile, Chars, L0) ->
|
||||
{match,St,Len} = regexp:first_match(Chars, "[^ \t]+"),
|
||||
%% io:fwrite("RE = ~p~n", [string:substr(Chars, St, Len)]),
|
||||
case collect_rule(Ifile, string:substr(Chars, St+Len), L0, []) of
|
||||
{ok,[{':',Lc}|Toks],L1} -> {ok,string:substr(Chars, St, Len),Toks,L1};
|
||||
{ok,Toks,L1} -> {error,{L0,leex,bad_rule}};
|
||||
{eof,L1} -> {error,{L1,leex,bad_rule}};
|
||||
{error,E,L1} -> {error,E}
|
||||
end.
|
||||
|
||||
collect_rule(Ifile, Chars, L0, Cont0) ->
|
||||
case erl_scan:tokens(Cont0, Chars, L0) of
|
||||
{done,{ok,Toks,L1},Rest} -> {ok,Toks,L0};
|
||||
{done,{eof,L1},Rest} -> {eof,L0};
|
||||
{done,{error,E,L1},Rest} -> {error,E,L0};
|
||||
{more,Cont1} ->
|
||||
collect_rule(Ifile, io:get_line(Ifile, leex), L0+1, Cont1)
|
||||
end.
|
||||
|
||||
parse_rules(Ifile, {ok,[$E,$r,$l,$a,$n,$g,$ ,$c,$o,$d,$e,$.|_Rest],L},
|
||||
Ms, REAs, As, N) ->
|
||||
%% Must be careful to put rules in correct order!
|
||||
parse_code(Ifile, L, reverse(REAs), reverse(As));
|
||||
parse_rules(Ifile, {ok,Chars,L0}, Ms, REAs, As, N) ->
|
||||
%% io:fwrite("~w: ~p~n", [L0,Chars]),
|
||||
case collect_rule(Ifile, Chars, L0) of
|
||||
{ok,Re,Atoks,L1} ->
|
||||
case parse_rule(Re, L0, Atoks, Ms, N) of
|
||||
{ok,REA,A} ->
|
||||
parse_rules(Ifile, nextline(Ifile, L1), Ms,
|
||||
[REA|REAs], [A|As], N+1);
|
||||
{error,E} -> {error,E}
|
||||
end;
|
||||
{error,E} -> {error,E}
|
||||
end;
|
||||
parse_rules(Ifile, {eof,Line}, Ms, REAs, As, N) ->
|
||||
%% Must be careful to put rules in correct order!
|
||||
{ok,reverse(REAs),reverse(As),[]}.
|
||||
|
||||
%% parse_rule(RegExpString, RegExpLine, ActionTokens, Macros, Counter)
|
||||
%% Parse one regexp after performing macro substition.
|
||||
|
||||
parse_rule(S, Line, [{dot,Ld}], Ms, N) ->
|
||||
case parse_rule_regexp(S, Ms) of
|
||||
{ok,R} ->
|
||||
{ok,{R,N},{N,empty_action}};
|
||||
{error,E} ->
|
||||
{error,{Line,leex,{regexp,E}}}
|
||||
end;
|
||||
parse_rule(S, Line, Atoks, Ms, N) ->
|
||||
case parse_rule_regexp(S, Ms) of
|
||||
{ok,R} ->
|
||||
case erl_parse:parse_exprs(Atoks) of
|
||||
{ok,Aes} ->
|
||||
YYtext = keymember('YYtext', 3, Atoks),
|
||||
{ok,{R,N},{N,Aes,YYtext}};
|
||||
{error,E} ->
|
||||
{error,{Line,leex,{after_regexp,S}}}
|
||||
end;
|
||||
{error,E} ->
|
||||
{error,{Line,leex,{regexp,E}}}
|
||||
end.
|
||||
|
||||
parse_rule_regexp(RE0, [{M,Exp}|Ms]) ->
|
||||
case regexp:gsub(RE0, "{" ++ M ++ "}", Exp) of
|
||||
{ok,RE,N} -> parse_rule_regexp(RE, Ms);
|
||||
{error,E} -> parse_rule_regexp(RE0, Ms)
|
||||
end;
|
||||
parse_rule_regexp(RE, []) ->
|
||||
%% io:fwrite("RE = ~p~n", [RE]),
|
||||
regexp:parse(RE).
|
||||
|
||||
%% parse_code(File, Line, REAs, Actions)
|
||||
%% Parse the code section of the file.
|
||||
|
||||
parse_code(Ifile, Line, REAs, As) ->
|
||||
{ok,REAs,As,io:get_chars(Ifile, leex, 102400)}.
|
||||
|
||||
%% nextline(InputFile, PrevLineNo) -> {ok,Chars,LineNo} | {eof,LineNo}.
|
||||
%% Get the next line skipping comment lines and blank lines.
|
||||
|
||||
nextline(Ifile, L) ->
|
||||
case io:get_line(Ifile, leex) of
|
||||
eof -> {eof,L};
|
||||
Chars ->
|
||||
case skip(Chars, " \t\n") of
|
||||
[$%|_Rest] -> nextline(Ifile, L+1);
|
||||
[] -> nextline(Ifile, L+1);
|
||||
Other -> {ok,Chars,L+1}
|
||||
end
|
||||
end.
|
||||
|
||||
%% skip(Str, Cs) -> lists:dropwhile(fun (C) -> member(C, Cs) end, Str).
|
||||
|
||||
skip([C|Str], Cs) ->
|
||||
case member(C, Cs) of
|
||||
true -> skip(Str, Cs);
|
||||
false -> [C|Str]
|
||||
end;
|
||||
skip([], Cs) -> [].
|
||||
|
||||
%% build_combined_nfa(RegExpActionList) -> {NFA,FirstState}. Build
|
||||
%% the combined NFA using Thompson's construction straight out of the
|
||||
%% book. Build the separate NFAs in the same order as the rules so
|
||||
%% that the accepting have ascending states have ascending state
|
||||
%% numbers. Start numbering the states from 1 as we put the states
|
||||
%% in a tuple with the state number as the index.
|
||||
|
||||
build_combined_nfa(REAs) ->
|
||||
{NFA0,Firsts,Free} = build_nfa_list(REAs, [], [], 1),
|
||||
F = #nfa_state{no=Free,edges=epsilon_trans(Firsts)},
|
||||
{list_to_tuple(keysort(#nfa_state.no, [F|NFA0])),Free}.
|
||||
|
||||
build_nfa_list([{RE,Action}|REAs], NFA0, Firsts, Free0) ->
|
||||
{NFA1,Free1,First} = build_nfa(RE, Free0, Action),
|
||||
build_nfa_list(REAs, NFA1 ++ NFA0, [First|Firsts], Free1);
|
||||
build_nfa_list([], NFA, Firsts, Free) ->
|
||||
{NFA,reverse(Firsts),Free}.
|
||||
|
||||
epsilon_trans(Firsts) -> [ {epsilon,F} || F <- Firsts ].
|
||||
|
||||
%% {NFA,NextFreeState,FirstState} = build_nfa(RegExp, FreeState, Action)
|
||||
%% When building the NFA states for a ??? we don't build the end
|
||||
%% state, just allocate a State for it and return this state
|
||||
%% number. This allows us to avoid building unnecessary states for
|
||||
%% concatenation which would then have to be removed by overwriting
|
||||
%% an existing state.
|
||||
|
||||
build_nfa(RE, FreeState, Action) ->
|
||||
{NFA,N,Es} = build_nfa(RE, FreeState+1, FreeState, []),
|
||||
{[#nfa_state{no=Es,accept={accept,Action}}|NFA],N,FreeState}.
|
||||
|
||||
%% build_nfa(RegExp, NextState, FirstState, NFA) -> {NFA,NextState,EndState}.
|
||||
%% The NFA is a list of nfa_state is no predefined order. The state
|
||||
%% number of the returned EndState is already allocated!
|
||||
|
||||
build_nfa({'or',RE1,RE2}, N0, Fs, NFA0) ->
|
||||
{NFA1,N1,Es1} = build_nfa(RE1, N0+1, N0, NFA0),
|
||||
{NFA2,N2,Es2} = build_nfa(RE2, N1+1, N1, NFA1),
|
||||
Es = N2,
|
||||
{[#nfa_state{no=Fs,edges=[{epsilon,N0},{epsilon,N1}]},
|
||||
#nfa_state{no=Es1,edges=[{epsilon,Es}]},
|
||||
#nfa_state{no=Es2,edges=[{epsilon,Es}]}|NFA2],
|
||||
N2+1,Es};
|
||||
build_nfa({concat,RE1, RE2}, N0, Fs, NFA0) ->
|
||||
{NFA1,N1,Es1} = build_nfa(RE1, N0, Fs, NFA0),
|
||||
{NFA2,N2,Es2} = build_nfa(RE2, N1, Es1, NFA1),
|
||||
{NFA2,N2,Es2};
|
||||
build_nfa({kclosure,RE}, N0, Fs, NFA0) ->
|
||||
{NFA1,N1,Es1} = build_nfa(RE, N0+1, N0, NFA0),
|
||||
Es = N1,
|
||||
{[#nfa_state{no=Fs,edges=[{epsilon,N0},{epsilon,Es}]},
|
||||
#nfa_state{no=Es1,edges=[{epsilon,N0},{epsilon,Es}]}|NFA1],
|
||||
N1+1,Es};
|
||||
build_nfa({pclosure,RE}, N0, Fs, NFA0) ->
|
||||
{NFA1,N1,Es1} = build_nfa(RE, N0+1, N0, NFA0),
|
||||
Es = N1,
|
||||
{[#nfa_state{no=Fs,edges=[{epsilon,N0}]},
|
||||
#nfa_state{no=Es1,edges=[{epsilon,N0},{epsilon,Es}]}|NFA1],
|
||||
N1+1,Es};
|
||||
build_nfa({optional,RE}, N0, Fs, NFA0) ->
|
||||
{NFA1,N1,Es1} = build_nfa(RE, N0+1, N0, NFA0),
|
||||
Es = N1,
|
||||
{[#nfa_state{no=Fs,edges=[{epsilon,N0},{epsilon,Es}]},
|
||||
#nfa_state{no=Es1,edges=[{epsilon,Es}]}|NFA1],
|
||||
N1+1,Es};
|
||||
build_nfa({char_class,Cc}, N, Fs, NFA) ->
|
||||
{[#nfa_state{no=Fs,edges=[{char_class(Cc),N}]}|NFA],N+1,N};
|
||||
build_nfa({comp_class,Cc}, N, Fs, NFA) ->
|
||||
{[#nfa_state{no=Fs,edges=[{comp_class(Cc),N}]}|NFA],N+1,N};
|
||||
build_nfa(C, N, Fs, NFA) when integer(C) ->
|
||||
{[#nfa_state{no=Fs,edges=[{[C],N}]}|NFA],N+1,N}.
|
||||
|
||||
char_class(Cc) ->
|
||||
lists:foldl(fun ({C1,C2}, Set) -> union(seq(C1, C2), Set);
|
||||
(C, Set) -> add_element(C, Set) end, [], Cc).
|
||||
|
||||
comp_class(Cc) -> subtract(seq(0, 255), char_class(Cc)).
|
||||
|
||||
%% build_dfa(NFA, NfaFirstState) -> {DFA,DfaFirstState}.
|
||||
%% Build a DFA from an NFA using "subset construction". The major
|
||||
%% difference from the book is that we keep the marked and unmarked
|
||||
%% DFA states in seperate lists. New DFA states are added to the
|
||||
%% unmarked list and states are marked by moving them to the marked
|
||||
%% list. We assume that the NFA accepting state numbers are in
|
||||
%% ascending order for the rules and use ordsets to keep this order.
|
||||
|
||||
build_dfa(NFA, Nf) ->
|
||||
D = #dfa_state{no=0,nfa=eclosure([Nf], NFA)},
|
||||
{build_dfa([D], 1, [], NFA),0}.
|
||||
|
||||
%% build_dfa([UnMarked], NextState, [Marked], NFA) -> DFA.
|
||||
%% Traverse the unmarked states. Temporarily add the current unmarked
|
||||
%% state to the marked list before calculating translation, this is
|
||||
%% to avoid adding too many duplicate states. Add it properly to the
|
||||
%% marked list afterwards with correct translations.
|
||||
|
||||
build_dfa([U|Us0], N0, Ms, NFA) ->
|
||||
{Ts,Us1,N1} = build_dfa(255, U#dfa_state.nfa, Us0, N0, [], [U|Ms], NFA),
|
||||
M = U#dfa_state{trans=Ts,accept=accept(U#dfa_state.nfa, NFA)},
|
||||
build_dfa(Us1, N1, [M|Ms], NFA);
|
||||
build_dfa([], N, Ms, NFA) -> Ms.
|
||||
|
||||
%% build_dfa(Char, [NfaState], [Unmarked], NextState, [Transition], [Marked], NFA) ->
|
||||
%% [Marked].
|
||||
%% Foreach NFA state set calculate the legal translations. N.B. must
|
||||
%% search *BOTH* the unmarked and marked lists to check if DFA state
|
||||
%% already exists. By test characters downwards and prepending
|
||||
%% transitions we get the transition lists in ascending order.
|
||||
|
||||
build_dfa(C, Set, Us, N, Ts, Ms, NFA) when C >= 0 ->
|
||||
case eclosure(move(Set, C, NFA), NFA) of
|
||||
S when S /= [] ->
|
||||
case keysearch(S, #dfa_state.nfa, Us) of
|
||||
{value,#dfa_state{no=T}} ->
|
||||
build_dfa(C-1, Set, Us, N, [{C,T}|Ts], Ms, NFA);
|
||||
false ->
|
||||
case keysearch(S, #dfa_state.nfa, Ms) of
|
||||
{value,#dfa_state{no=T}} ->
|
||||
build_dfa(C-1, Set, Us, N, [{C,T}|Ts], Ms, NFA);
|
||||
false ->
|
||||
U = #dfa_state{no=N,nfa=S},
|
||||
build_dfa(C-1, Set, [U|Us], N+1, [{C,N}|Ts], Ms, NFA)
|
||||
end
|
||||
end;
|
||||
[] ->
|
||||
build_dfa(C-1, Set, Us, N, Ts, Ms, NFA)
|
||||
end;
|
||||
build_dfa(-1, Set, Us, N, Ts, Ms, NFA) ->
|
||||
{Ts,Us,N}.
|
||||
|
||||
%% eclosure([State], NFA) -> [State].
|
||||
%% move([State], Char, NFA) -> [State].
|
||||
%% These are straight out of the book. As eclosure uses ordsets then
|
||||
%% the generated state sets are in ascending order.
|
||||
|
||||
eclosure(Sts, NFA) -> eclosure(Sts, NFA, []).
|
||||
|
||||
eclosure([St|Sts], NFA, Ec) ->
|
||||
#nfa_state{edges=Es} = element(St, NFA),
|
||||
eclosure([ N || {epsilon,N} <- Es,
|
||||
nnot(is_element(N, Ec)) ] ++ Sts,
|
||||
NFA, add_element(St, Ec));
|
||||
eclosure([], NFA, Ec) -> Ec.
|
||||
|
||||
nnot(true) -> false;
|
||||
nnot(false) -> true.
|
||||
|
||||
move(Sts, C, NFA) ->
|
||||
[St || N <- Sts,
|
||||
{C1,St} <- (element(N, NFA))#nfa_state.edges,
|
||||
list(C1),
|
||||
member(C, C1) ].
|
||||
|
||||
%% accept([State], NFA) -> {accept,A} | noaccept.
|
||||
%% Scan down the state list until we find an accepting state.
|
||||
|
||||
accept([St|Sts], NFA) ->
|
||||
case element(St, NFA) of
|
||||
#nfa_state{accept={accept,A}} -> {accept,A};
|
||||
#nfa_state{accept=noaccept} -> accept(Sts, NFA)
|
||||
end;
|
||||
accept([], NFA) -> noaccept.
|
||||
|
||||
%% minimise_dfa(DFA, DfaFirst) -> {DFA,DfaFirst}.
|
||||
%% Minimise the DFA by removing equivalent states. We consider a
|
||||
%% state if both the transitions and the their accept state is the
|
||||
%% same. First repeatedly run throught the DFA state list removing
|
||||
%% equivalent states and updating remaining transitions with
|
||||
%% remaining equivalent state numbers. When no more reductions are
|
||||
%% possible then pack the remaining state numbers to get consecutive
|
||||
%% states.
|
||||
|
||||
minimise_dfa(DFA0, Df0) ->
|
||||
case min_dfa(DFA0) of
|
||||
{DFA1,[]} -> %No reduction!
|
||||
{DFA2,Rs} = pack_dfa(DFA1),
|
||||
{min_update(DFA2, Rs),min_use(Df0, Rs)};
|
||||
{DFA1,Rs} ->
|
||||
minimise_dfa(min_update(DFA1, Rs), min_use(Df0, Rs))
|
||||
end.
|
||||
|
||||
min_dfa(DFA) -> min_dfa(DFA, [], []).
|
||||
|
||||
min_dfa([D|DFA0], Rs0, MDFA) ->
|
||||
{DFA1,Rs1} = min_delete(DFA0, D#dfa_state.trans, D#dfa_state.accept,
|
||||
D#dfa_state.no, Rs0, []),
|
||||
min_dfa(DFA1, Rs1, [D|MDFA]);
|
||||
min_dfa([], Rs, MDFA) -> {MDFA,Rs}.
|
||||
|
||||
min_delete([#dfa_state{no=N,trans=T,accept=A}|DFA], T, A, NewN, Rs, MDFA) ->
|
||||
min_delete(DFA, T, A, NewN, [{N,NewN}|Rs], MDFA);
|
||||
min_delete([D|DFA], T, A, NewN, Rs, MDFA) ->
|
||||
min_delete(DFA, T, A, NewN, Rs, [D|MDFA]);
|
||||
min_delete([], T, A, NewN, Rs, MDFA) -> {MDFA,Rs}.
|
||||
|
||||
min_update(DFA, Rs) ->
|
||||
[ D#dfa_state{trans=min_update_trans(D#dfa_state.trans, Rs)} || D <- DFA ].
|
||||
|
||||
min_update_trans(Tr, Rs) ->
|
||||
[ {C,min_use(S, Rs)} || {C,S} <- Tr ].
|
||||
|
||||
min_use(Old, [{Old,New}|Reds]) -> New;
|
||||
min_use(Old, [R|Reds]) -> min_use(Old, Reds);
|
||||
min_use(Old, []) -> Old.
|
||||
|
||||
pack_dfa(DFA) -> pack_dfa(DFA, 0, [], []).
|
||||
|
||||
pack_dfa([D|DFA], NewN, Rs, PDFA) ->
|
||||
pack_dfa(DFA, NewN+1, [{D#dfa_state.no,NewN}|Rs], [D#dfa_state{no=NewN}|PDFA]);
|
||||
pack_dfa([], NewN, Rs, PDFA) -> {PDFA,Rs}.
|
||||
|
||||
%% out_file(FileName, Module, DFA, DfaStart, [Action], Code) -> ok | error.
|
||||
|
||||
out_file(OutFile, Out, DFA, DF, Actions, Code) ->
|
||||
io:fwrite("Writing file ~s, ", [OutFile]),
|
||||
case file:path_open([".", [code:lib_dir(),"/tools/include"]],
|
||||
"leex.hrl", read) of
|
||||
{ok,Ifile,Iname} ->
|
||||
case file:open(OutFile, write) of
|
||||
{ok,Ofile} ->
|
||||
out_file(Ifile, Ofile, Out, DFA, DF, Actions, Code),
|
||||
file:close(Ifile),
|
||||
file:close(Ofile),
|
||||
io:fwrite("ok~n"),
|
||||
ok;
|
||||
{error,E} ->
|
||||
file:close(Ifile),
|
||||
io:fwrite("open error~n"),
|
||||
error
|
||||
end;
|
||||
{error,R} ->
|
||||
io:fwrite("open error~n"),
|
||||
error
|
||||
end.
|
||||
|
||||
%% out_file(IncFile, OutFile, DFA, DfaStart, Actions, Code) -> ok.
|
||||
%% Copy the include file line by line substituting special lines with
|
||||
%% generated code. We cheat by only looking at the first 5
|
||||
%% characters.
|
||||
|
||||
out_file(Ifile, Ofile, Out, DFA, DF, Actions, Code) ->
|
||||
case io:get_line(Ifile, leex) of
|
||||
eof -> ok;
|
||||
Line ->
|
||||
case string:substr(Line, 1, 5) of
|
||||
"##mod" -> io:fwrite(Ofile, "-module(~w).~n", [Out]);
|
||||
"##cod" -> io:put_chars(Ofile, Code);
|
||||
"##dfa" -> out_dfa(Ofile, DFA, DF);
|
||||
"##act" -> out_actions(Ofile, Actions);
|
||||
Other -> io:put_chars(Ofile, Line)
|
||||
end,
|
||||
out_file(Ifile, Ofile, Out, DFA, DF, Actions, Code)
|
||||
end.
|
||||
|
||||
out_dfa(File, DFA, DF) ->
|
||||
io:fwrite(File, "yystate() -> ~w.~n~n", [DF]),
|
||||
foreach(fun (S) -> out_trans(File, S) end, DFA),
|
||||
io:fwrite(File, "yystate(S, Ics, Line, Tlen, Action, Alen) ->~n", []),
|
||||
io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,S}.~n~n", []).
|
||||
|
||||
out_trans(File, #dfa_state{no=N,trans=[],accept={accept,A}}) ->
|
||||
io:fwrite(File, "yystate(~w, Ics, Line, Tlen, Action, Alen) ->~n", [N]),
|
||||
io:fwrite(File, " {~w,Tlen,Ics,Line};~n", [A]);
|
||||
out_trans(File, #dfa_state{no=N,trans=Tr,accept={accept,A}}) ->
|
||||
foreach(fun (T) -> out_tran(File, N, A, T) end, pack_trans(Tr)),
|
||||
io:fwrite(File, "yystate(~w, Ics, Line, Tlen, Action, Alen) ->~n", [N]),
|
||||
io:fwrite(File, " {~w,Tlen,Ics,Line,~w};~n", [A,N]);
|
||||
out_trans(File, #dfa_state{no=N,trans=Tr,accept=noaccept}) ->
|
||||
foreach(fun (T) -> out_tran(File, N, T) end, pack_trans(Tr)),
|
||||
io:fwrite(File, "yystate(~w, Ics, Line, Tlen, Action, Alen) ->~n", [N]),
|
||||
io:fwrite(File, " {Action,Alen,Tlen,Ics,Line,~w};~n", [N]).
|
||||
|
||||
out_tran(File, N, A, {{Cf,Cl},S}) ->
|
||||
out_head(File, N, io_lib:write_char(Cf), io_lib:write_char(Cl)),
|
||||
out_body(File, S, "Line", "C", A);
|
||||
out_tran(File, N, A, {$\n,S}) ->
|
||||
out_head(File, N, "$\\n"),
|
||||
out_body(File, S, "Line+1", "$\\n", A);
|
||||
out_tran(File, N, A, {C,S}) ->
|
||||
Char = io_lib:write_char(C),
|
||||
out_head(File, N, Char),
|
||||
out_body(File, S, "Line", Char, A).
|
||||
|
||||
out_tran(File, N, {{Cf,Cl},S}) ->
|
||||
out_head(File, N, io_lib:write_char(Cf), io_lib:write_char(Cl)),
|
||||
out_body(File, S, "Line", "C");
|
||||
out_tran(File, N, {$\n,S}) ->
|
||||
out_head(File, N, "$\\n"),
|
||||
out_body(File, S, "Line+1", "$\\n");
|
||||
out_tran(File, N, {C,S}) ->
|
||||
Char = io_lib:write_char(C),
|
||||
out_head(File, N, Char),
|
||||
out_body(File, S, "Line", Char).
|
||||
|
||||
out_head(File, State, Char) ->
|
||||
io:fwrite(File, "yystate(~w, [~s|Ics], Line, Tlen, Action, Alen) ->\n",
|
||||
[State,Char]).
|
||||
|
||||
out_head(File, State, Min, Max) ->
|
||||
io:fwrite(File, "yystate(~w, [C|Ics], Line, Tlen, Action, Alen) when C >= ~s, C =< ~s ->\n",
|
||||
[State,Min,Max]).
|
||||
|
||||
out_body(File, Next, Line, C, Action) ->
|
||||
io:fwrite(File, " yystate(~w, Ics, ~s, Tlen+1, ~w, Tlen);\n",
|
||||
[Next,Line,Action]).
|
||||
|
||||
out_body(File, Next, Line, C) ->
|
||||
io:fwrite(File, " yystate(~w, Ics, ~s, Tlen+1, Action, Alen);\n",
|
||||
[Next,Line]).
|
||||
|
||||
%% pack_tran([{Char,State}]) -> [{Crange,State}] when
|
||||
%% Crange = {Char,Char} | Char.
|
||||
%% Pack the translation table into something more suitable for
|
||||
%% generating code. Ranges of characters with the same State are
|
||||
%% packed together, while solitary characters are left "as is". We
|
||||
%% KNOW how the pattern matching compiler works so solitary
|
||||
%% characters are stored before ranges. We do this using ordsets for
|
||||
%% for the packed table. Always break out $\n as solitary character.
|
||||
|
||||
pack_trans([{C,S}|Tr]) -> pack_trans(Tr, C, C, S, []);
|
||||
pack_trans([]) -> [].
|
||||
|
||||
pack_trans([{$\n,S1}|Tr], Cf, Cl, S, Pt) ->
|
||||
pack_trans(Cf, Cl, S, add_element({$\n,S1}, pack_trans(Tr)));
|
||||
pack_trans([{C,S}|Tr], Cf, Cl, S, Pt) when C == Cl + 1 ->
|
||||
pack_trans(Tr, Cf, C, S, Pt);
|
||||
pack_trans([{C,S1}|Tr], Cf, Cl, S, Pt) ->
|
||||
pack_trans(Tr, C, C, S1, pack_trans(Cf, Cl, S, Pt));
|
||||
pack_trans([], Cf, Cl, S, Pt) -> pack_trans(Cf, Cl, S, Pt).
|
||||
|
||||
pack_trans(Cf, Cf, S, Pt) -> add_element({Cf,S}, Pt);
|
||||
pack_trans(Cf, Cl, S, Pt) when Cl == Cf + 1 ->
|
||||
add_element({Cf,S}, add_element({Cl,S}, Pt));
|
||||
pack_trans(Cf, Cl, S, Pt) -> add_element({{Cf,Cl},S}, Pt).
|
||||
|
||||
out_actions(File, As) ->
|
||||
foreach(fun (A) -> out_action(File, A) end, As),
|
||||
io:fwrite(File, "yyaction(_, _, _, _) -> error.~n", []).
|
||||
|
||||
out_action(File, {A,empty_action}) ->
|
||||
io:fwrite(File, "yyaction(~w, YYlen, YYtcs, YYline) -> skip_token;~n", [A]);
|
||||
out_action(File, {A,Code,YYtext}) ->
|
||||
io:fwrite(File, "yyaction(~w, YYlen, YYtcs, YYline) ->~n", [A]),
|
||||
if
|
||||
YYtext == true ->
|
||||
io:fwrite(File, " YYtext = yypre(YYtcs, YYlen),~n", []);
|
||||
YYtext == false -> ok
|
||||
end,
|
||||
io:fwrite(File, " ~s;~n", [erl_pp:exprs(Code, 4, none)]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
%% THIS IS A PRE-RELEASE OF LEEX - RELEASED ONLY BECAUSE MANY PEOPLE
|
||||
%% WANTED IT - THE OFFICIAL RELEASE WILL PROVIDE A DIFFERENT INCOMPATIBLE
|
||||
%% AND BETTER INTERFACE - BE WARNED
|
||||
%% PLEASE REPORT ALL BUGS TO THE AUTHOR.
|
||||
|
||||
##module
|
||||
|
||||
-export([string/1,string/2,token/2,token/3,tokens/2,tokens/3]).
|
||||
-export([format_error/1]).
|
||||
|
||||
%% User code. This is placed here to allow extra attributes.
|
||||
##code
|
||||
|
||||
format_error({illegal,S}) -> ["illegal characters ",io_lib:write_string(S)];
|
||||
format_error({user,S}) -> S.
|
||||
|
||||
string(String) -> string(String, 1).
|
||||
|
||||
string(String, Line) -> string(String, Line, String, []).
|
||||
|
||||
%% string(InChars, Line, TokenChars, Tokens) ->
|
||||
%% {ok,Tokens,Line} | {error,ErrorInfo,Line}.
|
||||
|
||||
string([], L, [], Ts) -> %No partial tokens!
|
||||
{ok,yyrev(Ts),L};
|
||||
string(Ics0, L0, Tcs, Ts) ->
|
||||
case yystate(yystate(), Ics0, L0, 0, reject, 0) of
|
||||
{A,Alen,Ics1,L1} -> %Accepting end state
|
||||
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L1), Ts);
|
||||
{A,Alen,Ics1,L1,S1} -> %After an accepting state
|
||||
string_cont(Ics1, L1, yyaction(A, Alen, Tcs, L1), Ts);
|
||||
{reject,Alen,Tlen,Ics1,L1,S1} ->
|
||||
{error,{L1,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},L1};
|
||||
{A,Alen,Tlen,Ics1,L1,S1} ->
|
||||
string_cont(yysuf(Tcs, Alen), L1, yyaction(A, Alen, Tcs, L1), Ts)
|
||||
end.
|
||||
|
||||
%% string_cont(RestChars, Line, Token, Tokens)
|
||||
%% Test for and remove the end token wrapper.
|
||||
|
||||
string_cont(Rest, Line, {token,T}, Ts) ->
|
||||
string(Rest, Line, Rest, [T|Ts]);
|
||||
string_cont(Rest, Line, {end_token,T}, Ts) ->
|
||||
string(Rest, Line, Rest, [T|Ts]);
|
||||
string_cont(Rest, Line, skip_token, Ts) ->
|
||||
string(Rest, Line, Rest, Ts);
|
||||
string_cont(Rest, Line, {error,S}, Ts) ->
|
||||
{error,{Line,?MODULE,{user,S}},Line}.
|
||||
|
||||
%% token(Continuation, Chars, Line) ->
|
||||
%% {more,Continuation} | {done,ReturnVal,RestChars}.
|
||||
%% Must be careful when re-entering to append the latest characters to the
|
||||
%% after characters in an accept.
|
||||
|
||||
token(Cont, Chars) -> token(Cont, Chars, 1).
|
||||
|
||||
token([], Chars, Line) ->
|
||||
token(Chars, Line, yystate(), Chars, 0, reject, 0);
|
||||
token({Line,State,Tcs,Tlen,Action,Alen}, Chars, _) ->
|
||||
token(Chars, Line, State, Tcs ++ Chars, Tlen, Action, Alen).
|
||||
|
||||
%% token(InChars, Line, State, TokenChars, TokenLen, Accept) ->
|
||||
%% {more,Continuation} | {done,ReturnVal,RestChars}.
|
||||
|
||||
token(Ics0, L0, S0, Tcs, Tlen0, A0, Alen0) ->
|
||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
|
||||
{A1,Alen1,Ics1,L1} -> %Accepting end state
|
||||
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1));
|
||||
{A1,Alen1,[],L1,S1} -> %After an accepting state
|
||||
{more,{L1,S1,Tcs,Alen1,A1,Alen1}};
|
||||
{A1,Alen1,Ics1,L1,S1} ->
|
||||
token_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1));
|
||||
{A1,Alen1,Tlen1,[],L1,S1} -> %After a non-accepting state
|
||||
{more,{L1,S1,Tcs,Tlen1,A1,Alen1}};
|
||||
{reject,Alen1,Tlen1,eof,L1,S1} ->
|
||||
{done,{eof,L1},[]};
|
||||
{reject,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
{done,{error,{L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}},L1},Ics1};
|
||||
{A1,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
token_cont(yysuf(Tcs, Alen1), L1, yyaction(A1, Alen1, Tcs, L1))
|
||||
end.
|
||||
|
||||
%% tokens_cont(RestChars, Line, Token)
|
||||
%% Test if we have detected the end token, if so return done else continue.
|
||||
|
||||
token_cont(Rest, Line, {token,T}) ->
|
||||
{done,{ok,T,Line},Rest};
|
||||
token_cont(Rest, Line, {end_token,T}) ->
|
||||
{done,{ok,T,Line},Rest};
|
||||
token_cont(Rest, Line, skip_token) ->
|
||||
token(Rest, Line, yystate(), Rest, 0, reject, 0);
|
||||
token_cont(Rest, Line, {error,S}) ->
|
||||
{done,{error,{Line,?MODULE,{user,S}},Line},Rest}.
|
||||
|
||||
%% tokens(Continuation, Chars, Line) ->
|
||||
%% {more,Continuation} | {done,ReturnVal,RestChars}.
|
||||
%% Must be careful when re-entering to append the latest characters to the
|
||||
%% after characters in an accept.
|
||||
|
||||
tokens(Cont, Chars) -> tokens(Cont, Chars, 1).
|
||||
|
||||
tokens([], Chars, Line) ->
|
||||
tokens(Chars, Line, yystate(), Chars, 0, [], reject, 0);
|
||||
tokens({tokens,Line,State,Tcs,Tlen,Ts,Action,Alen}, Chars, _) ->
|
||||
tokens(Chars, Line, State, Tcs ++ Chars, Tlen, Ts, Action, Alen);
|
||||
tokens({skip_tokens,Line,State,Tcs,Tlen,Error,Action,Alen}, Chars, _) ->
|
||||
skip_tokens(Chars, Line, State, Tcs ++ Chars, Tlen, Error, Action, Alen).
|
||||
|
||||
%% tokens(InChars, Line, State, TokenChars, TokenLen, Tokens, Accept) ->
|
||||
%% {more,Continuation} | {done,ReturnVal,RestChars}.
|
||||
|
||||
tokens(Ics0, L0, S0, Tcs, Tlen0, Ts, A0, Alen0) ->
|
||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
|
||||
{A1,Alen1,Ics1,L1} -> %Accepting end state
|
||||
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1), Ts);
|
||||
{A1,Alen1,[],L1,S1} -> %After an accepting state
|
||||
{more,{tokens,L1,S1,Tcs,Alen1,Ts,A1,Alen1}};
|
||||
{A1,Alen1,Ics1,L1,S1} ->
|
||||
tokens_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1), Ts);
|
||||
{A1,Alen1,Tlen1,[],L1,S1} -> %After a non-accepting state
|
||||
{more,{tokens,L1,S1,Tcs,Tlen1,Ts,A1,Alen1}};
|
||||
{reject,Alen1,Tlen1,eof,L1,S1} ->
|
||||
{done,if Ts == [] -> {eof,L1};
|
||||
true -> {ok,yyrev(Ts),L1} end,[]};
|
||||
{reject,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
skip_tokens(yysuf(Tcs, Tlen1+1), L1,
|
||||
{L1,?MODULE,{illegal,yypre(Tcs, Tlen1+1)}});
|
||||
{A1,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
tokens_cont(yysuf(Tcs, Alen1), L1, yyaction(A1, Alen1, Tcs, L1), Ts)
|
||||
end.
|
||||
|
||||
%% tokens_cont(RestChars, Line, Token, Tokens)
|
||||
%% Test if we have detected the end token, if so return done else continue.
|
||||
|
||||
tokens_cont(Rest, Line, {token,T}, Ts) ->
|
||||
tokens(Rest, Line, yystate(), Rest, 0, [T|Ts], reject, 0);
|
||||
tokens_cont(Rest, Line, {end_token,T}, Ts) ->
|
||||
{done,{ok,yyrev(Ts, [T]),Line},Rest};
|
||||
tokens_cont(Rest, Line, skip_token, Ts) ->
|
||||
tokens(Rest, Line, yystate(), Rest, 0, Ts, reject, 0);
|
||||
tokens_cont(Rest, Line, {error,S}, Ts) ->
|
||||
skip_tokens(Rest, Line, {Line,?MODULE,{user,S}}).
|
||||
|
||||
%% token_skip(InChars, Line, Error) -> {done,ReturnVal,RestChars}.
|
||||
%% Skip tokens until an end token, junk everything and return the error.
|
||||
|
||||
%%skip_tokens(Ics, Line, Error) -> {done,{error,Error,Line},Ics}.
|
||||
|
||||
skip_tokens(Ics, Line, Error) ->
|
||||
skip_tokens(Ics, Line, yystate(), Ics, 0, Error, reject, 0).
|
||||
|
||||
%% skip_tokens(InChars, Line, State, TokenChars, TokenLen, Tokens, Accept) ->
|
||||
%% {more,Continuation} | {done,ReturnVal,RestChars}.
|
||||
|
||||
skip_tokens(Ics0, L0, S0, Tcs, Tlen0, Error, A0, Alen0) ->
|
||||
case yystate(S0, Ics0, L0, Tlen0, A0, Alen0) of
|
||||
{A1,Alen1,Ics1,L1} -> %Accepting end state
|
||||
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1), Error);
|
||||
{A1,Alen1,[],L1,S1} -> %After an accepting state
|
||||
{more,{skip_tokens,L1,S1,Tcs,Alen1,Error,A1,Alen1}};
|
||||
{A1,Alen1,Ics1,L1,S1} ->
|
||||
skip_cont(Ics1, L1, yyaction(A1, Alen1, Tcs, L1), Error);
|
||||
{A1,Alen1,Tlen1,[],L1,S1} -> %After a non-accepting state
|
||||
{more,{skip_tokens,L1,S1,Tcs,Tlen1,Error,A1,Alen1}};
|
||||
{reject,Alen1,Tlen1,eof,L1,S1} ->
|
||||
{done,{error,Error,L1},[]};
|
||||
{reject,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
skip_tokens(yysuf(Tcs, Tlen1), L1, Error);
|
||||
{A1,Alen1,Tlen1,Ics1,L1,S1} ->
|
||||
skip_cont(yysuf(Tcs, Alen1), L1, yyaction(A1, Alen1, Tcs, L1), Error)
|
||||
end.
|
||||
|
||||
%% skip_cont(RestChars, Line, Token, Error)
|
||||
%% Test if we have detected the end token, if so return done else continue.
|
||||
|
||||
skip_cont(Rest, Line, {token,T}, Error) ->
|
||||
skip_tokens(Rest, Line, yystate(), Rest, 0, Error, reject, 0);
|
||||
skip_cont(Rest, Line, {end_token,T}, Error) ->
|
||||
{done,{error,Error,Line},Rest};
|
||||
skip_cont(Rest, Line, {error,S}, Error) ->
|
||||
skip_tokens(Rest, Line, yystate(), Rest, 0, Error, reject, 0);
|
||||
skip_cont(Rest, Line, skip_token, Error) ->
|
||||
skip_tokens(Rest, Line, yystate(), Rest, 0, Error, reject, 0).
|
||||
|
||||
yyrev(L) -> yyrev(L, []).
|
||||
|
||||
yyrev([H|T], Acc) -> yyrev(T, [H|Acc]);
|
||||
yyrev([], Acc) -> Acc.
|
||||
|
||||
yypre([H|T], N) when N > 0 -> [H|yypre(T, N-1)];
|
||||
yypre(L, N) -> [].
|
||||
|
||||
yysuf([H|T], N) when N > 0 -> yysuf(T, N-1);
|
||||
yysuf(L, 0) -> L.
|
||||
|
||||
%% Generated state transition function.
|
||||
##dfa
|
||||
|
||||
%% Generated action function.
|
||||
##actions
|
||||
@@ -1,95 +0,0 @@
|
||||
-module(lin).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Linear algebra utilities."},
|
||||
{keywords, [linear,algebra]},
|
||||
{date,981103}]).
|
||||
|
||||
-export([pow/3, inv/2, solve/2, str2int/1, int2str/1, gcd/2]).
|
||||
|
||||
%% pow(A, B, M) => (A^B) mod M
|
||||
%% examples pow(9726,3533,11413) = 5761
|
||||
%% pow(5971,6597,11413) = 9726
|
||||
|
||||
pow(A, 1, M) ->
|
||||
A rem M;
|
||||
pow(A, 2, M) ->
|
||||
A*A rem M;
|
||||
pow(A, B, M) ->
|
||||
B1 = B div 2,
|
||||
B2 = B - B1,
|
||||
%% B2 = B1 or B1+1
|
||||
P = pow(A, B1, M),
|
||||
case B2 of
|
||||
B1 -> (P*P) rem M;
|
||||
_ -> (P*P*A) rem M
|
||||
end.
|
||||
|
||||
%% inv(A, B) = C | no_inverse
|
||||
%% computes C such that
|
||||
%% A*C mod B = 1
|
||||
%% computes A^-1 mod B
|
||||
%% examples inv(28, 75) = 67.
|
||||
%% inv(3533, 11200) = 6597
|
||||
%% inv(6597, 11200) = 3533
|
||||
|
||||
inv(A, B) ->
|
||||
case solve(A, B) of
|
||||
{X, Y} ->
|
||||
if X < 0 -> X + B;
|
||||
true -> X
|
||||
end;
|
||||
_ ->
|
||||
no_inverse
|
||||
end.
|
||||
|
||||
%% solve(A, B) => {X, Y} | insoluble
|
||||
%% solve the linear congruence
|
||||
%% A * X - B * Y = 1
|
||||
|
||||
%S tag1
|
||||
solve(A, B) ->
|
||||
case catch s(A,B) of
|
||||
insoluble -> insoluble;
|
||||
{X, Y} ->
|
||||
case A * X - B * Y of
|
||||
1 -> {X, Y};
|
||||
Other -> error
|
||||
end
|
||||
end.
|
||||
|
||||
s(A, 0) -> throw(insoluble);
|
||||
s(A, 1) -> {0, -1};
|
||||
s(A, -1) -> {0, 1};
|
||||
s(A, B) ->
|
||||
K1 = A div B,
|
||||
K2 = A - K1*B,
|
||||
{Tmp, X} = s(B, -K2),
|
||||
{X, K1 * X - Tmp}.
|
||||
%E tag1
|
||||
|
||||
|
||||
%% converts a string to a base 256 integer
|
||||
%% converts a base 256 integer to a string
|
||||
|
||||
%S tag2
|
||||
str2int(Str) -> str2int(Str, 0).
|
||||
|
||||
str2int([H|T], N) -> str2int(T, N*256+H);
|
||||
str2int([], N) -> N.
|
||||
|
||||
int2str(N) -> int2str(N, []).
|
||||
|
||||
int2str(N, L) when N =< 0 -> L;
|
||||
int2str(N, L) ->
|
||||
N1 = N div 256,
|
||||
H = N - N1 * 256,
|
||||
int2str(N1, [H|L]).
|
||||
%E tag2
|
||||
|
||||
%% greatest common denominator
|
||||
|
||||
gcd(A, B) when A < B -> gcd(B, A);
|
||||
gcd(A, 0) -> A;
|
||||
gcd(A, B) ->
|
||||
gcd(B, A rem B).
|
||||
@@ -1,92 +0,0 @@
|
||||
-module(primes).
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Prime number utilities."},
|
||||
{keywords, [prime, numbers]},
|
||||
{date,981103}]).
|
||||
|
||||
-export([make/1, make_prime/1, is_prime/1]).
|
||||
-compile(export_all).
|
||||
|
||||
%% make a prime with at least K decimal digits
|
||||
%% Here we use 'Bertrand's postulate, is that for every N > 3,
|
||||
%% there is a prime P satisfying N < P < 2N - 2
|
||||
%% This was proved by Tchebychef in 1850 (Erdos improved this proof
|
||||
%% in 1932)
|
||||
|
||||
%S tag4
|
||||
|
||||
make_prime(K) when K > 0 ->
|
||||
new_seed(),
|
||||
N = make(K),
|
||||
if N > 3 ->
|
||||
io:format("Generating a ~w digit prime ",[K]),
|
||||
MaxTries = N - 3,
|
||||
P1 = make_prime(MaxTries, N+1),
|
||||
io:format("~n",[]),
|
||||
P1;
|
||||
true ->
|
||||
make_prime(K)
|
||||
end.
|
||||
|
||||
make_prime(0, _) ->
|
||||
exit(impossible);
|
||||
make_prime(K, P) ->
|
||||
io:format(".",[]),
|
||||
case is_prime(P) of
|
||||
true -> P;
|
||||
false -> make_prime(K-1, P+1)
|
||||
end.
|
||||
%E tag4
|
||||
|
||||
%% make(N) -> a random integer with N digits.
|
||||
|
||||
%S tag1
|
||||
make(N) -> new_seed(), make(N, 0).
|
||||
|
||||
make(0, D) -> D;
|
||||
make(N, D) ->
|
||||
make(N-1, D*10 + (random:uniform(10)-1)).
|
||||
%E tag1
|
||||
|
||||
%% Fermat's little theorem says that if
|
||||
%% N is a prime and if A < N then
|
||||
%% A^N mod N = A
|
||||
|
||||
%S tag3
|
||||
is_prime(D) ->
|
||||
new_seed(),
|
||||
is_prime(D, 100).
|
||||
|
||||
is_prime(D, Ntests) ->
|
||||
N = length(integer_to_list(D)) -1,
|
||||
is_prime(Ntests, D, N).
|
||||
|
||||
is_prime(0, _, _) -> true;
|
||||
is_prime(Ntest, N, Len) ->
|
||||
K = random:uniform(Len),
|
||||
%% A is a random number less than N
|
||||
A = make(K),
|
||||
if
|
||||
A < N ->
|
||||
case lin:pow(A,N,N) of
|
||||
A -> is_prime(Ntest-1,N,Len);
|
||||
_ -> false
|
||||
end;
|
||||
true ->
|
||||
is_prime(Ntest, N, Len)
|
||||
end.
|
||||
%E tag3
|
||||
|
||||
new_seed() ->
|
||||
{_,_,X} = erlang:now(),
|
||||
{H,M,S} = time(),
|
||||
H1 = H * X rem 32767,
|
||||
M1 = M * X rem 32767,
|
||||
S1 = S * X rem 32767,
|
||||
put(random_seed, {H1,M1,S1}).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
-module(rsa_key).
|
||||
|
||||
-export([make_sig/1, make_sig/2]).
|
||||
|
||||
make_sig(Who, Len) when Len > 79 ->
|
||||
{Public, Private} = make_sig(Len),
|
||||
file:write_file(Who ++ ".pub", term_to_binary(Public)),
|
||||
file:write_file(Who ++ ".pri", term_to_binary(Private)),
|
||||
{keyfilecreated,for,Who}.
|
||||
|
||||
%% The "book" says ...
|
||||
%% 1. Bob generates two primes p and q
|
||||
%% 2. Bob computes n = pq and phi(n) = (p-1)*(q-1)
|
||||
%% 3. Bob chooses a random b(0 < b < phi(n)) such that
|
||||
%% gcd(b, phi(n)) = 1
|
||||
%% 4. Bob computes a = b^(-1) mod phi(n) using the Euclidean algorithm
|
||||
%% 5. Bob publishes n and b in a directory as his public key.
|
||||
|
||||
%S tag1
|
||||
make_sig(Len) ->
|
||||
%% generate two <Len> digit prime numbers
|
||||
P = primes:make_prime(Len),
|
||||
io:format("P = ~p~n", [P]),
|
||||
Q = primes:make_prime(Len),
|
||||
io:format("Q = ~p~n", [Q]),
|
||||
N = P*Q,
|
||||
io:format("N = ~p~n", [N]),
|
||||
Phi = (P-1)*(Q-1),
|
||||
%% now make B such that B < Phi and gcd(B, Phi) = 1
|
||||
B = b(Phi),
|
||||
io:format("Public key (B) = ~p~n", [B]),
|
||||
A = lin:inv(B, Phi),
|
||||
io:format("Private key (A) = ~p~n", [A]),
|
||||
{{B,N},{A,N}}.
|
||||
|
||||
b(Phi) ->
|
||||
io:format("Generating a public key B "),
|
||||
K = length(integer_to_list(Phi)) - 1,
|
||||
B = b(1, K, Phi),
|
||||
io:format("~n", []),
|
||||
B.
|
||||
|
||||
b(Try, K, Phi) ->
|
||||
io:format("."),
|
||||
B = primes:make(K),
|
||||
if
|
||||
B < Phi ->
|
||||
case lin:gcd(B, Phi) of
|
||||
1 -> B;
|
||||
_ -> b(Try+1, K, Phi)
|
||||
end;
|
||||
true ->
|
||||
b(Try, K, Phi)
|
||||
end.
|
||||
%E tag1
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
erl -boot /home/joe/erl/example_programs-2.0/examples-2.0/sos -environment `printenv` -load $1
|
||||
@@ -1,344 +0,0 @@
|
||||
-module(sos).
|
||||
|
||||
-doc([{author,joe},
|
||||
{title,"Simple OS written entirely in Erlang"},
|
||||
{keywords, [os]},
|
||||
{htmldoc, "sos.html"},
|
||||
{date,981012}]).
|
||||
|
||||
-export([main/0, % starts the system
|
||||
load_module/1, %
|
||||
log_error/1,
|
||||
make_server/3,
|
||||
cast/2,
|
||||
rpc/2,
|
||||
change_behaviour/2,
|
||||
keep_alive/2,
|
||||
make_global/2,
|
||||
on_exit/2,
|
||||
on_halt/1,
|
||||
stop_system/1,
|
||||
every/3,
|
||||
spawn_fun/1,
|
||||
spawn_link_fun/1,
|
||||
lookup/2,
|
||||
map/2,
|
||||
reverse/1,
|
||||
read/0,
|
||||
write/1,
|
||||
env/1,
|
||||
make_scripts/0
|
||||
]).
|
||||
|
||||
-export([internal_call/1]).
|
||||
|
||||
main() ->
|
||||
make_server(io,
|
||||
fun start_io/0, fun handle_io/2),
|
||||
make_server(code,
|
||||
const([init,erl_prim_loader]),
|
||||
fun handle_code/2),
|
||||
make_server(error_logger,
|
||||
const(0), fun handle_error_logger/2),
|
||||
make_server(halt_demon,
|
||||
const([]), fun handle_halt_demon/2),
|
||||
make_server(env,
|
||||
fun start_env/0, fun handle_env/2),
|
||||
load_module(error_handler),
|
||||
Mod = get_module_name(),
|
||||
load_module(Mod),
|
||||
run(Mod).
|
||||
|
||||
run(Mod) ->
|
||||
Pid = spawn_link(Mod, main, []),
|
||||
on_exit(Pid, fun(Why) -> stop_system(Why) end).
|
||||
|
||||
load_module(Mod) -> rpc(code, {load_module, Mod}).
|
||||
|
||||
handle_code({load_module, Mod}, Mods) ->
|
||||
case member(Mod, Mods) of
|
||||
true ->
|
||||
{already_loaded, Mods};
|
||||
false ->
|
||||
case primLoad(Mod) of
|
||||
ok ->
|
||||
{{ok,Mod}, [Mod|Mods]};
|
||||
Error ->
|
||||
{Error, Mods}
|
||||
end
|
||||
end.
|
||||
|
||||
primLoad(Module) ->
|
||||
Str = atom_to_list(Module),
|
||||
case erl_prim_loader:get_file(Str ++ ".jam") of
|
||||
{ok, Bin, FullName} ->
|
||||
case erlang:load_module(Module, Bin) of
|
||||
{module, Module} ->
|
||||
ok;
|
||||
{module, _} ->
|
||||
{error, wrong_module_in_binary};
|
||||
Other ->
|
||||
{error, {bad_object_code, Module}}
|
||||
end;
|
||||
error ->
|
||||
{error, {cannot_locate, Module}}
|
||||
|
||||
end.
|
||||
|
||||
log_error(Error) -> cast(error_logger, {log, Error}).
|
||||
|
||||
handle_error_logger({log, Error}, N) ->
|
||||
erlang:display({error, Error}),
|
||||
{ok, N+1}.
|
||||
|
||||
%S tag4
|
||||
on_halt(Fun) -> cast(halt_demon,{on_halt,Fun}).
|
||||
stop_system(Why) -> cast(halt_demon,{stop_system,Why}).
|
||||
%E tag4
|
||||
|
||||
handle_halt_demon({on_halt, Fun}, Funs) ->
|
||||
{ok, [Fun|Funs]};
|
||||
handle_halt_demon({stop_system, Why}, Funs) ->
|
||||
case Why of
|
||||
normal -> true;
|
||||
_ -> erlang:display({stopping_system,Why})
|
||||
end,
|
||||
map(fun(F) -> F() end, Funs),
|
||||
erlang:halt(),
|
||||
{ok, []}.
|
||||
|
||||
%S tag5
|
||||
read() -> rpc(io, read).
|
||||
write(X) -> rpc(io, {write, X}).
|
||||
%E tag5
|
||||
|
||||
start_io() ->
|
||||
Port = open_port({fd,0,1}, [eof, binary]),
|
||||
process_flag(trap_exit, true),
|
||||
{false, Port}.
|
||||
|
||||
handle_io(read, {true, Port}) ->
|
||||
{eof, {true, Port}};
|
||||
handle_io(read, {false, Port}) ->
|
||||
receive
|
||||
{Port, {data, Bytes}} ->
|
||||
{{ok, Bytes}, {false, Port}};
|
||||
{Port, eof} ->
|
||||
{eof, {true,Port}};
|
||||
{'EXIT', Port, badsig} ->
|
||||
handle_io(read, {false, Port});
|
||||
{'EXIT', Port, Why} ->
|
||||
{eof, {true, Port}}
|
||||
end;
|
||||
handle_io({write,X}, {Flag,Port}) ->
|
||||
Port ! {self(), {command, X}},
|
||||
{ok, {Flag, Port}}.
|
||||
|
||||
env(Key) -> rpc(env, {lookup, Key}).
|
||||
|
||||
handle_env({lookup, Key}, Dict) ->
|
||||
{lookup(Key, Dict), Dict}.
|
||||
|
||||
start_env() ->
|
||||
Env = case init:get_argument(environment) of
|
||||
{ok, [L]} ->
|
||||
L;
|
||||
error ->
|
||||
fatal({missing, '-environment ...'})
|
||||
end,
|
||||
map(fun split_env/1, Env).
|
||||
|
||||
split_env(Str) -> split_env(Str, []).
|
||||
|
||||
split_env([$=|T], L) -> {reverse(L), T};
|
||||
split_env([], L) -> {reverse(L), []};
|
||||
split_env([H|T], L) -> split_env(T, [H|L]).
|
||||
|
||||
make_server(Name, FunD, FunH) ->
|
||||
make_global(Name,
|
||||
fun() ->
|
||||
Data = FunD(),
|
||||
server_loop(Name, Data, FunH)
|
||||
end).
|
||||
|
||||
server_loop(Name, Data, Fun) ->
|
||||
receive
|
||||
{rpc, Pid, Q} ->
|
||||
case (catch Fun(Q, Data)) of
|
||||
{'EXIT', Why} ->
|
||||
Pid ! {Name, exit, Why},
|
||||
server_loop(Name, Data, Fun);
|
||||
{Reply, Data1} ->
|
||||
Pid ! {Name, Reply},
|
||||
server_loop(Name, Data1, Fun)
|
||||
end;
|
||||
{cast, Pid, Q} ->
|
||||
case (catch Fun(Q, Data)) of
|
||||
{'EXIT', Why} ->
|
||||
exit(Pid, Why),
|
||||
server_loop(Name, Data, Fun);
|
||||
Data1 ->
|
||||
server_loop(Name, Data1, Fun)
|
||||
end;
|
||||
{eval, Fun1} ->
|
||||
server_loop(Name, Data, Fun1)
|
||||
end.
|
||||
|
||||
rpc(Name, Q) ->
|
||||
Name ! {rpc, self(), Q},
|
||||
receive
|
||||
{Name, Reply} ->
|
||||
Reply;
|
||||
{Name, exit, Why} ->
|
||||
exit(Why)
|
||||
end.
|
||||
|
||||
cast(Name, Q) ->
|
||||
Name ! {cast, self(), Q}.
|
||||
|
||||
change_behaviour(Name, Fun) ->
|
||||
Name ! {eval, Fun}.
|
||||
|
||||
const(C) -> fun() -> C end.
|
||||
|
||||
keep_alive(Name, Fun) ->
|
||||
Pid = make_global(Name, Fun),
|
||||
on_exit(Pid,
|
||||
fun(Exit) -> keep_alive(Name, Fun) end).
|
||||
|
||||
make_global(Name, Fun) ->
|
||||
case whereis(Name) of
|
||||
undefined ->
|
||||
Self = self(),
|
||||
Pid = spawn_fun(fun() ->
|
||||
make_global(Self,Name,Fun)
|
||||
end),
|
||||
receive
|
||||
{Pid, ack} ->
|
||||
Pid
|
||||
end;
|
||||
Pid ->
|
||||
Pid
|
||||
end.
|
||||
|
||||
make_global(Pid, Name, Fun) ->
|
||||
case register(Name, self()) of
|
||||
{'EXIT', _} ->
|
||||
Pid ! {self(), ack};
|
||||
_ ->
|
||||
Pid ! {self(), ack},
|
||||
Fun()
|
||||
end.
|
||||
|
||||
spawn_fun({'fun',Mod,Arity,Chksum,Env}) ->
|
||||
spawn(?MODULE, internal_call,
|
||||
[[Mod,Arity,Chksum,[],Env]]).
|
||||
|
||||
spawn_link_fun({'fun',Mod,Arity,Chksum,Env}) ->
|
||||
spawn(?MODULE, internal_call,
|
||||
[[Mod,Arity,Chksum,[],Env]]).
|
||||
|
||||
internal_call([Mod|Args]) ->
|
||||
apply(Mod, module_lambdas, Args).
|
||||
|
||||
on_exit(Pid, Fun) ->
|
||||
spawn_fun(fun() ->
|
||||
process_flag(trap_exit, true),
|
||||
link(Pid),
|
||||
receive
|
||||
{'EXIT', Pid, Why} ->
|
||||
Fun(Why)
|
||||
end
|
||||
end).
|
||||
|
||||
every(Pid, Time, Fun) ->
|
||||
spawn_fun(fun() ->
|
||||
process_flag(trap_exit, true),
|
||||
link(Pid),
|
||||
every_loop(Pid, Time, Fun)
|
||||
end).
|
||||
|
||||
every_loop(Pid, Time, Fun) ->
|
||||
receive
|
||||
{'EXIT', Pid, Why} ->
|
||||
true
|
||||
after Time ->
|
||||
Fun(),
|
||||
every_loop(Pid, Time, Fun)
|
||||
end.
|
||||
|
||||
get_module_name() ->
|
||||
case init:get_argument(load) of
|
||||
{ok, [[Arg]]} ->
|
||||
module_name(Arg);
|
||||
error ->
|
||||
fatal({missing, '-load Mod'})
|
||||
end.
|
||||
|
||||
%S tag7
|
||||
lookup(Key, [{Key,Val}|_]) -> {found, Val};
|
||||
lookup(Key, [_|T]) -> lookup(Key, T);
|
||||
lookup(Key, []) -> not_found.
|
||||
|
||||
member(X, [X|_]) -> true;
|
||||
member(H, [_|T]) -> member(H, T);
|
||||
member(_, []) -> false.
|
||||
|
||||
map(F, [H|T]) -> [F(H)|map(F, T)];
|
||||
map(F, []) -> [].
|
||||
|
||||
reverse(X) -> reverse(X, []).
|
||||
|
||||
reverse([H|T], L) -> reverse(T, [H|L]);
|
||||
reverse([], L) -> L.
|
||||
|
||||
module_name(Str) ->
|
||||
case (catch list_to_atom(Str)) of
|
||||
{'EXIT', _} ->
|
||||
log_error({bad_module_name,Str}),
|
||||
stop_system(bad_start_module);
|
||||
Mod -> Mod
|
||||
end.
|
||||
%E tag7
|
||||
|
||||
fatal(Term) ->
|
||||
log_error({fatal, Term}),
|
||||
stop_system({fatal, Term}).
|
||||
|
||||
%S tag8
|
||||
make_scripts() ->
|
||||
{ok, Cwd} = file:get_cwd(),
|
||||
Script =
|
||||
{script,{"sos","1.0"},
|
||||
[{preLoaded,[init,erl_prim_loader]},
|
||||
{progress,preloaded},
|
||||
{path,
|
||||
[".",
|
||||
Cwd,
|
||||
"$ROOT/lib/" ++ lib_location(kernel) ++ "/ebin",
|
||||
"$ROOT/lib/" ++ lib_location(stdlib) ++ "/ebin"]},
|
||||
{primLoad,
|
||||
[erl_open_port,
|
||||
erlang,
|
||||
error_handler,
|
||||
sos
|
||||
]},
|
||||
{kernel_load_completed},
|
||||
{progress,kernel_load_completed},
|
||||
{progress,started},
|
||||
{apply,{sos,main,[]}}
|
||||
]},
|
||||
file:write_file("sos.boot", term_to_binary(Script)),
|
||||
|
||||
{ok, Stream} = file:open("sos", write),
|
||||
io:format(Stream, "#!/bin/sh~nerl -boot ~s/sos "
|
||||
" -environment `printenv` -load $1~n",
|
||||
[Cwd]),
|
||||
file:close(Stream),
|
||||
unix:cmd("chmod a+x sos"),
|
||||
true.
|
||||
|
||||
lib_location(Lib) ->
|
||||
filename:basename(code:lib_dir(Lib)).
|
||||
%E tag8
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
-module(sos_err1).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
|
||||
main() ->
|
||||
listsforeaack:abc(123),
|
||||
sos:write("Hello world\n").
|
||||
@@ -1,7 +0,0 @@
|
||||
-module(sos_err2).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
|
||||
main() ->
|
||||
lists:abc(123),
|
||||
sos:write("Hello world\n").
|
||||
@@ -1,6 +0,0 @@
|
||||
-module(sos_test1).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
|
||||
main() ->
|
||||
sos:write("Hello world\n").
|
||||
@@ -1,7 +0,0 @@
|
||||
-module(sos_test2).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
|
||||
main() ->
|
||||
X = lists:reverse("Hellow world"),
|
||||
sos:write([X,"\n"]).
|
||||
@@ -1,16 +0,0 @@
|
||||
-module(sos_test3).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
-import(sos, [read/0, write/1]).
|
||||
|
||||
main() ->
|
||||
loop().
|
||||
|
||||
loop() ->
|
||||
case read() of
|
||||
eof ->
|
||||
true;
|
||||
{ok, X} ->
|
||||
write([X]),
|
||||
loop()
|
||||
end.
|
||||
@@ -1,8 +0,0 @@
|
||||
-module(sos_test4).
|
||||
-doc(none).
|
||||
-export([main/0]).
|
||||
|
||||
main() ->
|
||||
sos:write("I will crash now\n"),
|
||||
1 = 2,
|
||||
sos:write("This line will not be printed\n").
|
||||
@@ -1,8 +0,0 @@
|
||||
Suffix .erl.jam ->
|
||||
c:c($>).
|
||||
|
||||
Suffix .tex.dvi ->
|
||||
unix:cmd("latex $>.tex").
|
||||
|
||||
Suffix .ehtml.html ->
|
||||
ehtml:file("$>").
|
||||
@@ -1,17 +0,0 @@
|
||||
%% This is a macro
|
||||
|
||||
OBJS = a.jam, b.jam.
|
||||
|
||||
OBJS += ,c.jam.
|
||||
|
||||
include("suffix_rules").
|
||||
|
||||
all when a.dvi $(OBJS).
|
||||
|
||||
a.dvi when a.tex ->
|
||||
|
||||
io:format("touching a.dvi~n"),
|
||||
unix:cmd("touch a.dvi"),
|
||||
io:format("done~n").
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
%% This is a macro
|
||||
|
||||
OBJS = abc.jam, a.jam, b.jam.
|
||||
|
||||
include("$(MAKEDIR)/suffix_rules").
|
||||
|
||||
all when $(OBJS) a.dvi.
|
||||
|
||||
a.dvi when a.tex ->
|
||||
unix:cmd("touch a.dvi").
|
||||
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
%%
|
||||
%% Make the tk library
|
||||
%%
|
||||
|
||||
Jamdir=../ebin.
|
||||
|
||||
CC = gcc.
|
||||
|
||||
tk when $(Jamdir)/tk.jam, $(Jamdir)/tkfocus.jam,
|
||||
tkbutton.jam, tkentry.jam,
|
||||
tkscrlbar.jam, tkdialog.jam, tklib.jam ->
|
||||
X = 12,
|
||||
Y = 14,
|
||||
tk:stop(X, Y, X+Y).
|
||||
|
||||
$(Jamdir)/tk.jam when tk.erl, tk.hrl ->
|
||||
c:c(tk, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
$(Jamdir)/tkfocus.jam when tkfocus.erl, tk.hrl ->
|
||||
c:c(tkfocus, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
$(Jamdir)/tkbutton.jam when tkbutton.erl, tk.hrl ->
|
||||
c:c(tkbutton, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
$(Jamdir)/tkentry.jam when tkentry.erl, tk.hrl ->
|
||||
c:c(tkentry, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
tkscrlbar.jam when tkscrlbar.erl, tk.hrl ->
|
||||
c:c(tkscrlbar, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
tkdialog.jam when tkdialog.erl ->
|
||||
c:c(tkdialog, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
tklib.jam when tklib.erl ->
|
||||
io:format("compiling: $@~n"),
|
||||
c:c(tklib, [{outdir, "$(Jamdir)"}]).
|
||||
|
||||
foo.o when foo.c ->
|
||||
unix:cmd("$(CC) -o $@ -c foo.c").
|
||||
|
||||
foo when bar ->
|
||||
X = case Jamdir of
|
||||
"../ebin" -> 1;
|
||||
".." -> 2;
|
||||
"." -> 3
|
||||
end,
|
||||
io:format("this = ~w", [X]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
all when a.jam ->
|
||||
p,q,r.
|
||||
|
||||
all -> a,b,c.
|
||||
|
||||
all,b,c when a,b,c.
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
\begin{titlepage}
|
||||
\begin{center}
|
||||
\vspace*{1.0cm}
|
||||
{\Huge\bf
|
||||
The Erlang Cookbook\\
|
||||
}
|
||||
|
||||
\vskip 1.0 true cm
|
||||
|
||||
|
||||
\vskip 3.0 true cm
|
||||
|
||||
{\large\bf
|
||||
Joe Armstrong\\
|
||||
}
|
||||
|
||||
\vskip 1.0 true cm
|
||||
|
||||
\end{center}
|
||||
\eject
|
||||
\end{titlepage}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
-module(topological_sort).
|
||||
|
||||
%% Copyright (C) 1998, Ericsson Computer Science Laboratory
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Topological sort of a partial order."},
|
||||
{keywords, [topological,sort,partial,order]},
|
||||
{date,981102}]).
|
||||
|
||||
|
||||
-export([sort/1, test/0]).
|
||||
|
||||
-import(lists, [map/2, member/2, filter/2]).
|
||||
|
||||
%% -type([{X, X}]) -> {ok, [{X,Y}]} | {cycle, [{X,Y}]}
|
||||
%% topological_sort:pairs(L)
|
||||
|
||||
%% A partial order on the set S is a set of pairs {Xi,Xj} such that
|
||||
%% some relation between Xi and Xj is obeyed.
|
||||
|
||||
%% A topological sort of a partial order is a sequence of elements
|
||||
%% [X1, X2, X3 ...] such that if whenever {Xi, Xj} is in the partial
|
||||
%% order i < j
|
||||
|
||||
test() ->
|
||||
Pairs = [{1,2},{2,4},{4,6},{2,10},{4,8},{6,3},{1,3},
|
||||
{3,5},{5,8},{7,5},{7,9},{9,4},{9,10}],
|
||||
sort(Pairs).
|
||||
|
||||
%% [7,1,9,2,4,6,3,5,8,10]
|
||||
%S tag1
|
||||
sort(Pairs) ->
|
||||
iterate(Pairs, [], all(Pairs)).
|
||||
|
||||
iterate([], L, All) ->
|
||||
{ok, remove_duplicates(L ++ subtract(All, L))};
|
||||
iterate(Pairs, L, All) ->
|
||||
case subtract(lhs(Pairs), rhs(Pairs)) of
|
||||
[] ->
|
||||
{cycle, Pairs};
|
||||
Lhs ->
|
||||
iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All)
|
||||
end.
|
||||
|
||||
all(L) -> lhs(L) ++ rhs(L).
|
||||
lhs(L) -> map(fun({X,_}) -> X end, L).
|
||||
rhs(L) -> map(fun({_,Y}) -> Y end, L).
|
||||
|
||||
%% subtract(L1, L2) -> all the elements in L1 which are not in L2
|
||||
|
||||
subtract(L1, L2) -> filter(fun(X) -> not member(X, L2) end, L1).
|
||||
|
||||
remove_duplicates([H|T]) ->
|
||||
case member(H, T) of
|
||||
true -> remove_duplicates(T);
|
||||
false -> [H|remove_duplicates(T)]
|
||||
end;
|
||||
remove_duplicates([]) ->
|
||||
[].
|
||||
|
||||
%% remove_pairs(L1, L2) -> L2' L1 = [X] L2 = [{X,Y}]
|
||||
%% removes all pairs from L2 where the first element
|
||||
%% of each pair is a member of L1
|
||||
|
||||
remove_pairs(L1, L2) -> filter(fun({X,Y}) -> not member(X, L1) end, L2).
|
||||
%E tag1
|
||||
@@ -1,39 +0,0 @@
|
||||
-module(transitive).
|
||||
%% Copyright (C) 1997, Ericsson Telecom AB
|
||||
|
||||
-doc([{author,'Joe Armstrong'},
|
||||
{title,"Transitive closure of a graph."},
|
||||
{keywords, [transitive,closure]},
|
||||
{date,981102}]).
|
||||
|
||||
%% warning slow on big graphs
|
||||
|
||||
-export([closure/2]).
|
||||
|
||||
%S tag1
|
||||
closure(RootSet, Pairs) ->
|
||||
closure_list(RootSet, Pairs, RootSet).
|
||||
|
||||
closure(Start, [], L) ->
|
||||
L;
|
||||
closure(Start, Pairs, Reachable) ->
|
||||
{Next, Rest} = next(Start, Pairs),
|
||||
closure_list(Next, Rest, Next ++ Reachable).
|
||||
|
||||
closure_list([], Pairs, Reachable) ->
|
||||
Reachable;
|
||||
closure_list([H|T], Pairs, Reachable) ->
|
||||
Reachable1 = closure(H, Pairs, Reachable),
|
||||
closure_list(T, Pairs, Reachable1).
|
||||
|
||||
next(Start, Pairs) ->
|
||||
next(Start, Pairs, [], []).
|
||||
|
||||
next(Start, [], Reach, NoReach) ->
|
||||
{Reach, NoReach};
|
||||
next(Start, [{Start,Next}|T], Reach, NoReach) ->
|
||||
next(Start, T, [Next|Reach], NoReach);
|
||||
next(Start, [H|T], Reach, NoReach) ->
|
||||
next(Start, T, Reach, [H|NoReach]).
|
||||
%E tag1
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
{"joe", "zapme"}.
|
||||
{"ftp","ftp"}.
|
||||
{"jane","hospan"}.
|
||||
@@ -1,7 +0,0 @@
|
||||
block data
|
||||
integer nmax
|
||||
parameter (nmax=20)
|
||||
real v(nmax), alpha, beta
|
||||
common /vector/v,alpha,beta
|
||||
data v/20*100.0/, alpha/3.14/, beta/2.71/
|
||||
end
|
||||
@@ -1,150 +0,0 @@
|
||||
c<html>
|
||||
c<body>
|
||||
c<pre>
|
||||
module constants
|
||||
integer, parameter :: np=2000, dbl=selected_real_kind(14,100)
|
||||
real(dbl) :: g=9.807,dtmin=.001
|
||||
end module constants
|
||||
c
|
||||
program fall
|
||||
use constants
|
||||
implicit none
|
||||
c
|
||||
c Program to calculate the dynamics of a falling body
|
||||
c
|
||||
c John Mahaffy 4/15/95
|
||||
c
|
||||
c Arrays:
|
||||
c v - velocity at each time integration step
|
||||
c z - height at each time integration step
|
||||
c t - time for each corresponding v and z
|
||||
c zreal - Actual height at time t(i) for comparison with computed z
|
||||
c
|
||||
c In this program, I am using allocatate just to save space in the
|
||||
c executable program file (a.out). No attempt is made to estimate a size.
|
||||
c Module "constants" communicates between subroutines.
|
||||
c
|
||||
c<a name="alable"><font color="FF0000">
|
||||
real(dbl), allocatable :: v(:),z(:),t(:), zreal(:)
|
||||
c</font></a>
|
||||
real(dbl) dt
|
||||
integer nsteps
|
||||
c<a name="all"><font color="FF0000">
|
||||
allocate (v(np),z(np),t(np),zreal(np))
|
||||
c</font></a>
|
||||
call input(z,dt)
|
||||
call odesolve(v,z,t,dt,nsteps)
|
||||
call realans(t,z,nsteps,zreal)
|
||||
call output (t,z,zreal,v,nsteps)
|
||||
stop
|
||||
end
|
||||
c
|
||||
subroutine input (z,dt)
|
||||
use constants
|
||||
implicit none
|
||||
c
|
||||
c Obtain user input for initial height and time step
|
||||
c
|
||||
c John Mahaffy 4/15/95
|
||||
c
|
||||
c Output Arguments:
|
||||
c z(1) - initial height
|
||||
c dt - integration time step
|
||||
c
|
||||
real(dbl) z(*),dt
|
||||
c
|
||||
write(6,'(a)',advance='no') ' Initial height (meters): '
|
||||
read *, z(1)
|
||||
write(6,'(a)',advance='no') 'Time step size (seconds): '
|
||||
read *, dt
|
||||
if(dt.le.0.) dt=dtmin
|
||||
return
|
||||
end
|
||||
c
|
||||
subroutine odesolve(v,z,t,dt,nsteps)
|
||||
use constants
|
||||
c
|
||||
c Solve the Ordinary Differential Equation of motion for the body
|
||||
c
|
||||
c John Mahaffy 4/15/95
|
||||
c
|
||||
c Arguments:
|
||||
c Input
|
||||
c dt - timestep size
|
||||
c Output:
|
||||
c v - velocity
|
||||
c z - height
|
||||
c t - time
|
||||
c nsteps - last step in the integration
|
||||
c
|
||||
real (dbl) v(*),z(*),t(*),dt
|
||||
integer i, nsteps
|
||||
c
|
||||
c Solve the equation for a falling body
|
||||
c
|
||||
c d v d z
|
||||
c --- = - g --- = v
|
||||
c d t d t
|
||||
c
|
||||
c Set remaining initial conditions:
|
||||
c
|
||||
t(1)=0.
|
||||
v(1)=0.
|
||||
c
|
||||
c Now loop through time steps until z goes negative or we run out of space
|
||||
c
|
||||
do 100 i=2,np
|
||||
v(i)= v(i-1)-dt*g
|
||||
z(i)= z(i-1)+dt*.5*(v(i)+v(i-1))
|
||||
t(i)=t(i-1)+dt
|
||||
if(z(i).lt.0.) go to 200
|
||||
c<a name="con"><font color="FF0000">
|
||||
100 continue
|
||||
c</font></a>
|
||||
write(6,*) 'Ran out of space to continue integration'
|
||||
write(6,*) ' Last height was ',z(np),' meters'
|
||||
i=np
|
||||
200 nsteps=i
|
||||
c return
|
||||
end
|
||||
c
|
||||
subroutine realans(t,z,nsteps,zreal)
|
||||
use constants
|
||||
c
|
||||
c Get the values of the analytic solution to the differential equation
|
||||
c for each time point to check the numerical accuracy.
|
||||
c
|
||||
c John Mahaffy 4/15/95
|
||||
c
|
||||
real(dbl) t(*),z(*),zreal(*)
|
||||
integer i,nsteps
|
||||
c
|
||||
do 10 i=1,nsteps
|
||||
10 zreal(i)=z(1)-.5*g*t(i)**2
|
||||
return
|
||||
end
|
||||
c
|
||||
subroutine output(t,z,zreal,v,nsteps)
|
||||
use constants, only : dbl
|
||||
implicit none
|
||||
c
|
||||
c Outputs the full results of the time integration
|
||||
c
|
||||
c John Mahaffy 4/15/95
|
||||
c
|
||||
real(dbl) v(*),z(*),t(*), zreal(*)
|
||||
integer nsteps,i
|
||||
print *, 'Results are in fall.output'
|
||||
open (11,file='fall.output')
|
||||
write(11,2000)
|
||||
do 300 i=1,nsteps
|
||||
write(11,2001) t(i),v(i),z(i),zreal(i)
|
||||
300 continue
|
||||
2000 format (33x,'Computed',8x,'Actual',/,
|
||||
& 6x,'Time',9x,'Velocity', 8x,'Height',8x,'Height')
|
||||
2001 format (1x,1p,4e15.7)
|
||||
return
|
||||
end
|
||||
c</pre>
|
||||
c</body>
|
||||
c</html>
|
||||
@@ -1,55 +0,0 @@
|
||||
program htcoef
|
||||
c
|
||||
c John Mahaffy, Penn State University, CmpSc 201 Example
|
||||
c 1/26/96
|
||||
c
|
||||
implicit none
|
||||
real k,D,Pr,h,Nulam,Nuturb
|
||||
real Re1,Re2,Re3,Re4
|
||||
c
|
||||
c Calculate an approximation for heat transfer coefficients
|
||||
c in a 1 inch pipe for several different Reynolds numbers
|
||||
c
|
||||
c An example of why you should learn to use subprograms
|
||||
c
|
||||
c h - heat transfer coefficient ( w/m**2/K)'
|
||||
c Nulam - laminar Nusselt number
|
||||
c Nuturb - Turbulent Nusselt number (Dittus-Boelter correlation)
|
||||
c k - conductivity ( w/m/K)'
|
||||
c D - hydraulic diameter (m)
|
||||
c Re - Reynolds number
|
||||
c Pr - Prandl number
|
||||
c
|
||||
data k,D,Pr/0.617,0.0254,1.0/, Nulam/4.0/
|
||||
c
|
||||
c Each of the following blocks assigns a Reynolds number, calculates
|
||||
c an associated Turbulent Nusselt number and calculates the heat
|
||||
c transfer coefficient based on the maximum of Turbulent and Laminar
|
||||
c Nusselt Numbers
|
||||
c
|
||||
Re1=10.
|
||||
Nuturb=0.023*Re1**0.8*Pr**0.4
|
||||
h=k/D*max(Nulam,Nuturb)
|
||||
print *, 'For Reynolds Number = ',Re1
|
||||
print *, 'Heat Transfer Coefficient is ',h,' w/m**2/K'
|
||||
c
|
||||
Re2=100.
|
||||
Nuturb=0.023*Re2**0.8*Pr**0.4
|
||||
h=k/D*max(Nulam,Nuturb)
|
||||
print *, 'For Reynolds Number = ',Re2
|
||||
print *, 'Heat Transfer Coefficient is ',h,' w/m**2/K'
|
||||
c
|
||||
Re3=1000.
|
||||
Nuturb=0.023*Re3**0.8*Pr**0.4
|
||||
h=k/D*max(Nulam,Nuturb)
|
||||
print *, 'For Reynolds Number = ',Re3
|
||||
print *, 'Heat Transfer Coefficient is ',h,' w/m**2/K'
|
||||
c
|
||||
Re4=10000.
|
||||
Nuturb=0.023*Re4**0.8*Pr**0.4
|
||||
h=k/D*max(Nulam,Nuturb)
|
||||
print *, 'For Reynolds Number = ',Re4
|
||||
print *, 'Heat Transfer Coefficient is ',h,' w/m**2/K'
|
||||
c
|
||||
stop
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
subroutine linint(x,y)
|
||||
c
|
||||
c Given a value of x return a value of y based on interpolation
|
||||
c within a table of y values (ytab) evaluated at evenly spaced
|
||||
c x points between xmin and xmax.
|
||||
c
|
||||
c John Mahaffy 2/12/95
|
||||
c
|
||||
real ytab(11)
|
||||
parameter (xmin=300.,dx=100.,xmax=xmin+10.*dx,rdx=1./dx)
|
||||
data ytab/1.0,2.1,3.2,4.4,5.7,7.1,8.6,10.2,11.9,13.7,15.8/
|
||||
if(x.ge.xmin.and.x.le.xmax) then
|
||||
i1= int((x-xmin)*rdx)+1
|
||||
x1=xmin+(i1-1)*dx
|
||||
wx=(x-x1)*rdx
|
||||
y=(1-wx)*ytab(i1)+wx*ytab(i1+1)
|
||||
else
|
||||
write(6,*) 'x = ', x, ' is out of table range'
|
||||
stop
|
||||
endif
|
||||
return
|
||||
end
|
||||
@@ -1,209 +0,0 @@
|
||||
c<html>
|
||||
c<head><title>plot2.f</title></head>
|
||||
c<body>
|
||||
c<pre>
|
||||
|
||||
program plotit
|
||||
c
|
||||
c Program to provide plots of Sin(x)
|
||||
c Ascii Character plots go to terminal and file 'pplot.out'
|
||||
c
|
||||
c John Mahaffy 2/1/95
|
||||
c
|
||||
implicit none
|
||||
c
|
||||
c The following line tells Fortran that "func" is a function or subroutine
|
||||
c and not a variable
|
||||
c
|
||||
c<a name="ex"><font color="FF0000">
|
||||
external func
|
||||
c</font></a>
|
||||
c
|
||||
c The next line is necessary to pass the location of the intrinsic sin
|
||||
c function as an argument to a subprogram
|
||||
c
|
||||
c<a name="intrinsic"><font color="FF0000">
|
||||
intrinsic sin
|
||||
c</font></a>
|
||||
c
|
||||
call pplot(func,0.,6.)
|
||||
print *, 'Hit the Enter key to continue'
|
||||
c<a name="pause"><font color="FF0000">
|
||||
pause
|
||||
c</font></a>
|
||||
call gnuplot('x','y','sin(x)',func,0.0,6.0)
|
||||
call gnuplot('x','y','Intrinsic sin(x)',sin,0.0,6.0)
|
||||
stop
|
||||
end
|
||||
subroutine pplot(f,xmin,xmax)
|
||||
c
|
||||
c Generate ASCII character plot to screen and file 'pplot.out'
|
||||
c
|
||||
implicit none
|
||||
character line*72
|
||||
real x, f , xmin , xmax
|
||||
integer ip,i,imax
|
||||
c
|
||||
c The following line tells Fortran that f is a function or subroutine
|
||||
c and not a variable
|
||||
c
|
||||
external f
|
||||
c
|
||||
c INPUT Arguments
|
||||
c
|
||||
c f - function to be ploted
|
||||
c xmin - minimum x value
|
||||
c xmax - maximum x value
|
||||
c
|
||||
c OTHER key variables
|
||||
c
|
||||
c line - Character string loaded with a line of output
|
||||
c ip - Position in line for a function value
|
||||
c
|
||||
open (11,file='pplot.out')
|
||||
c
|
||||
c Label values of the y axis
|
||||
c
|
||||
line=' '
|
||||
line(14:15)='-1'
|
||||
line(65:65)='1'
|
||||
write(*,*) line
|
||||
write(11,*) line
|
||||
line=' '
|
||||
write(line(10:13),'(f4.1)') xmin
|
||||
c
|
||||
c Draw the y axis
|
||||
c
|
||||
line(15:40)='+----+----+----+----+----+'
|
||||
line(41:65)=line(16:40)
|
||||
c
|
||||
c Plot the value at x=0
|
||||
c
|
||||
ip= nint(25*f(0.0))+40
|
||||
line(ip:ip)='*'
|
||||
write(*,*) line
|
||||
write(11,*) line
|
||||
line=' '
|
||||
imax=nint((xmax-xmin)*10)
|
||||
c
|
||||
c Limit output
|
||||
c
|
||||
imax=min(1000,imax)
|
||||
c
|
||||
c Loop through and plot points for other x values
|
||||
c
|
||||
do 50 i=1,imax
|
||||
x=.1*i
|
||||
ip=nint(25*f(x))+40
|
||||
c
|
||||
if(mod(i,10).eq.0) then
|
||||
write(line(10:13),'(f4.1)') x
|
||||
line(40:40)='+'
|
||||
c<a name="else"><font color="FF0000">
|
||||
else
|
||||
c</font></a>
|
||||
line(10:13)=' '
|
||||
line(40:40)='|'
|
||||
endif
|
||||
line(ip:ip)='*'
|
||||
write(*,*) line
|
||||
write(11,*) line
|
||||
50 line(ip:ip)=' '
|
||||
c<a name="close"><font color="FF0000">
|
||||
close (11)
|
||||
c</font></a>
|
||||
return
|
||||
end
|
||||
subroutine gnuplot(xlabel,ylabel,title,f,xmin,xmax)
|
||||
c
|
||||
c Ship data to the public domain program "gnuplot" for plotting
|
||||
c
|
||||
implicit none
|
||||
character line*72,sq*1
|
||||
real x,f,xmin,xmax,fx
|
||||
character*(*) xlabel,ylabel,title
|
||||
integer i,imax,lc
|
||||
external f
|
||||
data sq/''''/
|
||||
c
|
||||
c INPUT Arguments
|
||||
c
|
||||
c f - function to be ploted
|
||||
c xmin - minimum x value
|
||||
c xmax - maximum x value
|
||||
c xlabel - Contains a label for the x-axis
|
||||
c ylabel - Contains a label for the y-axis
|
||||
c title - Contains a title for the plot
|
||||
c
|
||||
c OTHER key variables
|
||||
c
|
||||
c line - Contains a line of character data
|
||||
c
|
||||
c Drive a separate true graphics program (gnuplot)
|
||||
c
|
||||
c First set up the command file for gnuplot
|
||||
c Run gnuplot interactively and use the "help" command to learn more
|
||||
c about what I am doing.
|
||||
c
|
||||
open (12,file='gnuxy')
|
||||
c
|
||||
c UnComment the next line if you are on a NCSA/BYU Telnet Session
|
||||
c
|
||||
c write(12,*) 'set terminal tek40xx'
|
||||
c
|
||||
write(12,*) 'set data style lines'
|
||||
c <a name=1><font color=FF0000>
|
||||
lc=len(xlabel)
|
||||
c </font>
|
||||
line='set xlabel '''//xlabel(1:lc)//sq
|
||||
write(12,*)line
|
||||
c
|
||||
c You don't really need to calculate the character variable length
|
||||
c here. The following works just fine because of the character*(*)
|
||||
c
|
||||
line='set ylabel '''//ylabel//sq
|
||||
write(12,*)line
|
||||
line='set title '''//title//sq
|
||||
write(12,*)line
|
||||
write(12,*)'set nokey'
|
||||
write(12,2000) xmin,xmax
|
||||
2000 format('set xrange [',f3.0,':',f3.0,']')
|
||||
write(12,*) 'plot ''dataxy'' using 1:2'
|
||||
write(12,*) 'pause 10'
|
||||
close(12)
|
||||
c
|
||||
c Generate x-y pairs for the graph
|
||||
c
|
||||
open (12,file='dataxy')
|
||||
imax=nint((xmax-xmin)*10)
|
||||
c
|
||||
c Limit output
|
||||
c
|
||||
imax=min(1000,imax)
|
||||
c
|
||||
do 100 i=0,imax
|
||||
x=.1*i
|
||||
fx=f(x)
|
||||
write(12,*) x,fx
|
||||
100 continue
|
||||
close(12)
|
||||
c
|
||||
c Tell the system to run the program gnuplot
|
||||
c This call works on either IBM RS6000 or Sun, but is not part of
|
||||
c the Fortran standard.
|
||||
c Comment out the line if you aren't at a terminal with graphics
|
||||
c
|
||||
call system('gnuplot gnuxy')
|
||||
c<a name="10"><font color="FF0000">
|
||||
return
|
||||
c</a></font>
|
||||
end
|
||||
c<a name="fun"><font color="FF0000">
|
||||
real function func(x)
|
||||
c</font></a>
|
||||
func=sin(x)
|
||||
return
|
||||
end
|
||||
c</pre>
|
||||
c</body>
|
||||
c</html>
|
||||
@@ -1,73 +0,0 @@
|
||||
function thcl(temp)
|
||||
c
|
||||
c function thcl evaluates the freon liquid thermal conductivity
|
||||
c as a function of liquid enthalpy
|
||||
c
|
||||
c liquid temperature temp in (j/kg)
|
||||
c thermal conductivity thcl in (w/m/k)
|
||||
c
|
||||
c
|
||||
c
|
||||
dimension tabl(4,26)
|
||||
save ilast
|
||||
data ilast/15/,ntab/26/
|
||||
data tabl/
|
||||
& 1.99826700E+02, 1.15267000E-01,-3.03660304E-04, 6.96601393E-07,
|
||||
& 2.10937800E+02, 1.11979000E-01,-2.88180288E-04, 6.96601393E-07,
|
||||
& 2.22048900E+02, 1.08863000E-01,-2.72700273E-04,-6.88501377E-07,
|
||||
& 2.33160000E+02, 1.05748000E-01,-2.88000288E-04, 6.88501377E-07,
|
||||
& 2.44271100E+02, 1.02633000E-01,-2.72700273E-04,-6.96601393E-07,
|
||||
& 2.55382200E+02, 9.95170000E-02,-2.88180288E-04, 7.04701409E-07,
|
||||
& 2.66493300E+02, 9.64020000E-02,-2.72520273E-04,-7.04701409E-07,
|
||||
& 2.77604400E+02, 9.32870000E-02,-2.88180288E-04, 6.96822277E-07,
|
||||
& 2.88715600E+02, 9.01710000E-02,-2.72695225E-04,-6.88955687E-07,
|
||||
& 2.99826700E+02, 8.70560000E-02,-2.88005336E-04, 6.88955687E-07,
|
||||
& 3.10937800E+02, 8.39410000E-02,-2.72695225E-04,-6.97055703E-07,
|
||||
& 3.22048900E+02, 8.08250000E-02,-2.88185336E-04, 7.05155719E-07,
|
||||
& 3.33160000E+02, 7.77100000E-02,-2.72515225E-04,-7.05155719E-07,
|
||||
& 3.44271100E+02, 7.45950000E-02,-2.88185336E-04, 6.97055703E-07,
|
||||
& 3.55382200E+02, 7.14790000E-02,-2.72695225E-04,-6.88955687E-07,
|
||||
& 3.66493300E+02, 6.83640000E-02,-2.88005336E-04, 6.88955687E-07,
|
||||
& 3.77604400E+02, 6.52490000E-02,-2.72695225E-04,-6.96822277E-07,
|
||||
& 3.88715600E+02, 6.21330000E-02,-2.88180288E-04, 7.04701409E-07,
|
||||
& 3.99826700E+02, 5.90180000E-02,-2.72520273E-04,-7.04701409E-07,
|
||||
& 4.10937800E+02, 5.59030000E-02,-2.88180288E-04, 6.96601393E-07,
|
||||
& 4.22048900E+02, 5.27870000E-02,-2.72700273E-04,-4.89240978E-06,
|
||||
& 4.33160000E+02, 4.91530000E-02,-3.81420381E-04, 6.80401361E-07,
|
||||
& 4.44271100E+02, 4.49990000E-02,-3.66300366E-04,-6.28561257E-06,
|
||||
& 4.55382200E+02, 4.01530000E-02,-5.05980506E-04,-2.45592491E-05,
|
||||
& 4.66493300E+02, 3.14990000E-02,-1.05174105E-03,-2.18924207E-04,
|
||||
& 4.70937800E+02, 2.25000000E-02, 0.00000000E+00, 0.00000000E+00/
|
||||
x=temp
|
||||
c Start the search from the last point of table use index
|
||||
c
|
||||
if (x.le.tabl(1,ilast+1)) then
|
||||
c
|
||||
c Search down the table from point of last use
|
||||
c
|
||||
do 20 i1=ilast,1,-1
|
||||
if(x.ge.tabl(1,i1)) go to 60
|
||||
20 continue
|
||||
c write(6,*) 'x = ', x, ' is below the table range'
|
||||
i1=1
|
||||
go to 60
|
||||
else
|
||||
c
|
||||
c Search up the table from point of last use
|
||||
c
|
||||
do 40 i1=ilast+1,ntab-1
|
||||
if(x.le.tabl(1,i1+1)) go to 60
|
||||
40 continue
|
||||
c write(6,*) 'x = ', x, ' is above the table range'
|
||||
i1=ntab-1
|
||||
go to 60
|
||||
endif
|
||||
c
|
||||
c Bounding points found, interpolate
|
||||
c
|
||||
60 dx=(x-tabl(1,i1))
|
||||
thcl=tabl(2,i1)+tabl(3,i1)*dx+tabl(4,i1)*dx**2
|
||||
ilast=i1
|
||||
120 continue
|
||||
return
|
||||
end
|
||||
@@ -1,46 +0,0 @@
|
||||
// This file is part of the Java Compiler Kit (JKit)
|
||||
//
|
||||
// The Java Compiler Kit is free software; you can
|
||||
// redistribute it and/or modify it under the terms of the
|
||||
// GNU General Public License as published by the Free Software
|
||||
// Foundation; either version 2 of the License, or (at your
|
||||
// option) any later version.
|
||||
//
|
||||
// The Java Compiler Kit 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 General Public License
|
||||
// for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public
|
||||
// License along with the Java Compiler Kit; if not,
|
||||
// write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
// Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// (C) David James Pearce, 2009.
|
||||
|
||||
package jkit.jil.dfa;
|
||||
|
||||
public interface FlowSet {
|
||||
|
||||
/**
|
||||
* FlowSets must be cloneable to facilitate multiple flows of execution
|
||||
* from conditionals
|
||||
*
|
||||
* @return A Clone of the current FlowSet
|
||||
*/
|
||||
public Object clone();
|
||||
|
||||
/**
|
||||
* Computes the least upper bound of this flowset and that provided. <b>NOTE</b>
|
||||
* the join operation has a subtle, yet important, requirement. If the
|
||||
* result of the join must be equivalent to *this* flowset, then it must be
|
||||
* the *same* flowset.
|
||||
*
|
||||
* @param s
|
||||
* Another FlowSet to join with this
|
||||
* @return true if this FlowSet has changed due to the computation, false
|
||||
* otherwise
|
||||
*/
|
||||
public FlowSet join(FlowSet s);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
/**
|
||||
* A Ship square represents a square that contains a battle ship, but has not
|
||||
* yet been bombed. Ship Squares can be either visible or invisible (depending
|
||||
* on which side they are).
|
||||
*
|
||||
* @author djp
|
||||
*/
|
||||
public class ShipSquare extends GridSquare {
|
||||
private BattleShip ship;
|
||||
private Type type;
|
||||
|
||||
public enum Type {
|
||||
VERTICAL_TOP_END,
|
||||
HORIZONTAL_MIDDLE
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a ShipSquare representing part of a battle ship (either a
|
||||
* middle or end piece).
|
||||
*
|
||||
*/
|
||||
public ShipSquare(Type type, BattleShip ship) {
|
||||
this.type = type;
|
||||
this.ship = ship;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ship that this square is part of.
|
||||
* @return
|
||||
*/
|
||||
public BattleShip getShip() { return ship; }
|
||||
|
||||
/**
|
||||
* Determine what part of the ship this piece represents.
|
||||
* @return
|
||||
*/
|
||||
public Type getType() { return type; }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
$(function(){
|
||||
window.Todo = Backbone.Model.extend({
|
||||
defaults: function() {
|
||||
return {
|
||||
done: false,
|
||||
order: Todos.nextOrder()
|
||||
};
|
||||
},
|
||||
|
||||
// Toggle the `done` state of this todo item.
|
||||
toggle: function() {
|
||||
this.save({done: !this.get("done")});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
// base class
|
||||
var Animal = Class.create({
|
||||
initialize: function(name) {
|
||||
this.name = name;
|
||||
},
|
||||
name: "",
|
||||
eat: function() {
|
||||
return this.say("Yum!");
|
||||
},
|
||||
say: function(message) {
|
||||
return this.name + ": " + message;
|
||||
}
|
||||
});
|
||||
|
||||
// subclass that augments a method
|
||||
var Cat = Class.create(Animal, {
|
||||
eat: function($super, food) {
|
||||
if (food instanceof Mouse) return $super();
|
||||
else return this.say("Yuk! I only eat mice.");
|
||||
}
|
||||
});
|
||||
|
||||
// empty subclass
|
||||
var Mouse = Class.create(Animal, {});
|
||||
|
||||
//mixins
|
||||
var Sellable = {
|
||||
getValue: function(pricePerKilo) {
|
||||
return this.weight * pricePerKilo;
|
||||
},
|
||||
|
||||
inspect: function() {
|
||||
return '#<Sellable: #{weight}kg>'.interpolate(this);
|
||||
}
|
||||
};
|
||||
|
||||
var Reproduceable = {
|
||||
reproduce: function(partner) {
|
||||
if (partner.constructor != this.constructor || partner.sex == this.sex)
|
||||
return null;
|
||||
var weight = this.weight / 10, sex = Math.random(1).round() ? 'male' : 'female';
|
||||
return new this.constructor('baby', weight, sex);
|
||||
}
|
||||
};
|
||||
|
||||
// base class with mixin
|
||||
var Plant = Class.create(Sellable, {
|
||||
initialize: function(name, weight) {
|
||||
this.name = name;
|
||||
this.weight = weight;
|
||||
},
|
||||
|
||||
inspect: function() {
|
||||
return '#<Plant: #{name}>'.interpolate(this);
|
||||
}
|
||||
});
|
||||
|
||||
// subclass with mixin
|
||||
var Dog = Class.create(Animal, Reproduceable, {
|
||||
initialize: function($super, name, weight, sex) {
|
||||
this.weight = weight;
|
||||
this.sex = sex;
|
||||
$super(name);
|
||||
}
|
||||
});
|
||||
|
||||
// subclass with mixins
|
||||
var Ox = Class.create(Animal, Sellable, Reproduceable, {
|
||||
initialize: function($super, name, weight, sex) {
|
||||
this.weight = weight;
|
||||
this.sex = sex;
|
||||
$super(name);
|
||||
},
|
||||
|
||||
eat: function(food) {
|
||||
if (food instanceof Plant)
|
||||
this.weight += food.weight;
|
||||
},
|
||||
|
||||
inspect: function() {
|
||||
return '#<Ox: #{name}>'.interpolate(this);
|
||||
}
|
||||
});
|
||||
107
tests/javascript/jquery.ui.progressbar.js
vendored
107
tests/javascript/jquery.ui.progressbar.js
vendored
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* jQuery UI Progressbar @VERSION
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Progressbar
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.core.js
|
||||
* jquery.ui.widget.js
|
||||
*/
|
||||
(function( $, undefined ) {
|
||||
|
||||
$.widget( "ui.progressbar", {
|
||||
options: {
|
||||
value: 0,
|
||||
max: 100
|
||||
},
|
||||
|
||||
min: 0,
|
||||
|
||||
_create: function() {
|
||||
this.element
|
||||
.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
|
||||
.attr({
|
||||
role: "progressbar",
|
||||
"aria-valuemin": this.min,
|
||||
"aria-valuemax": this.options.max,
|
||||
"aria-valuenow": this._value()
|
||||
});
|
||||
|
||||
this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
|
||||
.appendTo( this.element );
|
||||
|
||||
this.oldValue = this._value();
|
||||
this._refreshValue();
|
||||
},
|
||||
|
||||
_destroy: function() {
|
||||
this.element
|
||||
.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
|
||||
.removeAttr( "role" )
|
||||
.removeAttr( "aria-valuemin" )
|
||||
.removeAttr( "aria-valuemax" )
|
||||
.removeAttr( "aria-valuenow" );
|
||||
|
||||
this.valueDiv.remove();
|
||||
},
|
||||
|
||||
value: function( newValue ) {
|
||||
if ( newValue === undefined ) {
|
||||
return this._value();
|
||||
}
|
||||
|
||||
this._setOption( "value", newValue );
|
||||
return this;
|
||||
},
|
||||
|
||||
_setOption: function( key, value ) {
|
||||
if ( key === "value" ) {
|
||||
this.options.value = value;
|
||||
this._refreshValue();
|
||||
if ( this._value() === this.options.max ) {
|
||||
this._trigger( "complete" );
|
||||
}
|
||||
}
|
||||
|
||||
this._super( "_setOption", key, value );
|
||||
},
|
||||
|
||||
_value: function() {
|
||||
var val = this.options.value;
|
||||
// normalize invalid value
|
||||
if ( typeof val !== "number" ) {
|
||||
val = 0;
|
||||
}
|
||||
return Math.min( this.options.max, Math.max( this.min, val ) );
|
||||
},
|
||||
|
||||
_percentage: function() {
|
||||
return 100 * this._value() / this.options.max;
|
||||
},
|
||||
|
||||
_refreshValue: function() {
|
||||
var value = this.value();
|
||||
var percentage = this._percentage();
|
||||
|
||||
if ( this.oldValue !== value ) {
|
||||
this.oldValue = value;
|
||||
this._trigger( "change" );
|
||||
}
|
||||
|
||||
this.valueDiv
|
||||
.toggle( value > this.min )
|
||||
.toggleClass( "ui-corner-right", value === this.options.max )
|
||||
.width( percentage.toFixed(0) + "%" );
|
||||
this.element.attr( "aria-valuenow", value );
|
||||
}
|
||||
});
|
||||
|
||||
$.extend( $.ui.progressbar, {
|
||||
version: "@VERSION"
|
||||
});
|
||||
|
||||
})( jQuery );
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Object Literal Notation */
|
||||
var objectLiteral = {
|
||||
str: '1',
|
||||
func: function() { return 1; }
|
||||
};
|
||||
|
||||
/* Module Pattern 1 */
|
||||
var module = (function(){
|
||||
var private = 1;
|
||||
return {
|
||||
method: function() { private++; }
|
||||
};
|
||||
})();
|
||||
|
||||
/* Module Pattern 2 */
|
||||
var module2 = {};
|
||||
(function(context){
|
||||
var private = 1;
|
||||
context.method = function() { private++; }
|
||||
})(module2);
|
||||
|
||||
/* Module Pattern 3 */
|
||||
var module3 = {};
|
||||
(function(){
|
||||
var private = 1;
|
||||
this.method = function() { private++; }
|
||||
}).apply(module3);
|
||||
@@ -1,42 +0,0 @@
|
||||
// This example is from the book _JavaScript: The Definitive Guide_.
|
||||
// Written by David Flanagan. Copyright (c) 1996 O'Reilly & Associates.
|
||||
// This example is provided WITHOUT WARRANTY either expressed or implied.
|
||||
// You may study, use, modify, and distribute it for any purpose.
|
||||
|
||||
function Circle(radius) { // the constructor defines the class itself
|
||||
// r is an instance variable; defined and initialized in the constructor
|
||||
this.r = radius;
|
||||
}
|
||||
|
||||
// Circle.PI is a class variable--it is a property of the constructor function
|
||||
Circle.PI = 3.14159;
|
||||
|
||||
// Here is a function that computes a circle area.
|
||||
function Circle_area() { return Circle.PI * this.r * this.r; }
|
||||
|
||||
// Here we make the function into an instance method by assigning it
|
||||
// to the prototype object of the constructor. Remember that we have to
|
||||
// create and discard one object before the prototype object exists
|
||||
new Circle(0);
|
||||
Circle.prototype.area = Circle_area;
|
||||
|
||||
// Here's another function. It takes two circle objects are arguments and
|
||||
// returns the one that is larger (has the larger radius).
|
||||
function Circle_max(a,b) {
|
||||
if (a.r > b.r) return a;
|
||||
else return b;
|
||||
}
|
||||
|
||||
// Since this function compares two circle objects, it doesn't make sense as
|
||||
// an instance method operating on a single circle object. But we don't want
|
||||
// it to be a stand-alone function either, so we make it into a class method
|
||||
// by assigning it to the constructor function:
|
||||
Circle.max = Circle_max;
|
||||
|
||||
// Here is some code that uses each of these fields:
|
||||
c = new Circle(1.0); // create an instance of the Circle class
|
||||
c.r = 2.2; // set the r instance variable
|
||||
a = c.area(); // invoke the area() instance method
|
||||
x = Math.exp(Circle.PI); // use the PI class variable in our own computation.
|
||||
d = new Circle(1.2); // create another Circle instance
|
||||
bigger = Circle.max(c,d); // use the max() class method.
|
||||
6081
tests/javascript/prototype.js
vendored
6081
tests/javascript/prototype.js
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
var app = {
|
||||
foo: function(){},
|
||||
bar: function(){}
|
||||
}
|
||||
|
||||
var dsads = {
|
||||
fdfsd: function(){},
|
||||
dsadas: function(){}
|
||||
}
|
||||
@@ -1,597 +0,0 @@
|
||||
/* Test file for C++ language.
|
||||
* Attempt to include as many aspects of the C++ language as possible.
|
||||
* Do not include things tested in test.c since that shares the
|
||||
* same language.
|
||||
*
|
||||
* $Id: test.cpp,v 1.22 2008/05/17 20:12:55 zappo Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/* An include test */
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "c++-test.hh"
|
||||
|
||||
#include <c++-test.hh>
|
||||
|
||||
double var1 = 1.2;
|
||||
|
||||
int simple1(int a) {
|
||||
|
||||
}
|
||||
|
||||
struct foo1 {
|
||||
int test;
|
||||
};
|
||||
|
||||
struct foo2 : public foo1 {
|
||||
const int foo21(int a, int b);
|
||||
const int foo22(int a, int b) { return 1 }
|
||||
};
|
||||
|
||||
/* Classes */
|
||||
class class1 {
|
||||
private:
|
||||
int var11;
|
||||
struct foo1 var12;
|
||||
public:
|
||||
int p_var11;
|
||||
struct foo p_var12;
|
||||
};
|
||||
|
||||
class i_class1 : public class1 {
|
||||
private:
|
||||
int var11;
|
||||
struct foo var12;
|
||||
public:
|
||||
int p_var11;
|
||||
struct foo p_var12;
|
||||
};
|
||||
|
||||
class class2 {
|
||||
private:
|
||||
int var21;
|
||||
struct foo var22;
|
||||
public:
|
||||
int p_var21;
|
||||
struct foo p_var22;
|
||||
};
|
||||
|
||||
class i_class2 : public class1, public class2 {
|
||||
private:
|
||||
int var21;
|
||||
struct foo var22;
|
||||
protected:
|
||||
int pt_var21;
|
||||
public:
|
||||
int p_var21;
|
||||
struct foo p_var22;
|
||||
};
|
||||
|
||||
class class3 {
|
||||
/* A class with strange things in it */
|
||||
public:
|
||||
class3(); /* A constructor */
|
||||
enum embedded_foo_enum {
|
||||
a, b, c
|
||||
} embed1;
|
||||
struct embedded_bar_struct {
|
||||
int a;
|
||||
int b;
|
||||
} embed2;
|
||||
class embedded_baz_class {
|
||||
embedded_baz_class();
|
||||
~embedded_baz_class();
|
||||
} embed3;
|
||||
~class3(); /* destructor */
|
||||
|
||||
/* Methods */
|
||||
int method_for_class3(int a, char b);
|
||||
|
||||
int inline_method(int c) { return c; }
|
||||
|
||||
/* Operators */
|
||||
class3& operator^= (const class3& something);
|
||||
|
||||
/* Funny declmods */
|
||||
const class3 * const method_const_ptr_ptr(const int * const argconst) const = 0;
|
||||
};
|
||||
|
||||
class3::class3()
|
||||
{
|
||||
/* Constructor outside the definition. */
|
||||
}
|
||||
|
||||
int class3::method_for_class3(int a, char b)
|
||||
{
|
||||
}
|
||||
|
||||
int class3::method1_for_class3( int a, int &b)
|
||||
{
|
||||
int cvariablename;
|
||||
class3 fooy[];
|
||||
class3 moose = new class3;
|
||||
|
||||
// Complktion testing line should find external members.
|
||||
a = fooy[1].me ;
|
||||
b = cv ;
|
||||
|
||||
if (fooy.emb) {
|
||||
simple1(c);
|
||||
}
|
||||
|
||||
cos(10);
|
||||
abs(10);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char class3::method2_for_class3( int a, int b) throw ( exception1 )
|
||||
{
|
||||
return 'a';
|
||||
}
|
||||
|
||||
void *class3::method3_for_class3( int a, int b) throw ( exception1, exception2 )
|
||||
{
|
||||
int q = a;
|
||||
return "Moose";
|
||||
}
|
||||
|
||||
void *class3::method31_for_class3( int a, int b) throw ( )
|
||||
{
|
||||
int q = a;
|
||||
return "Moose";
|
||||
}
|
||||
|
||||
void *class3::method4_for_class3( int a, int b) reentrant
|
||||
{
|
||||
class3 ct;
|
||||
|
||||
ct.method5_for_class3(1,a);
|
||||
|
||||
pritf();
|
||||
}
|
||||
|
||||
/*
|
||||
* A method on class3.
|
||||
*/
|
||||
void *class3::method5_for_class3( int a, int b) const
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Namespace parsing tests
|
||||
*/
|
||||
namespace NS {
|
||||
class class_in_namespace {
|
||||
int equiv(const NS::class_in_namespace *) const;
|
||||
};
|
||||
}
|
||||
|
||||
int NS::class_in_namespace::equiv(const NS::class_in_namespace *cin) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stuff Klaus found.
|
||||
// Inheritance w/out a specifying for public.
|
||||
class class4 : class1 {
|
||||
// Pure virtual methods.
|
||||
void virtual print () const = 0;
|
||||
|
||||
public:
|
||||
// The whacky constructor type
|
||||
class4()
|
||||
try : class1(args)
|
||||
{
|
||||
// constructor body
|
||||
}
|
||||
catch ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class class5 : public virtual class4 {
|
||||
// Virtual inheritance
|
||||
};
|
||||
|
||||
class class6 : class1 {
|
||||
// Mutable
|
||||
mutable int i;
|
||||
};
|
||||
|
||||
/* Namespaces */
|
||||
namespace namespace1 {
|
||||
void ns_method1() { }
|
||||
|
||||
class n_class1 {
|
||||
public:
|
||||
void method11(int a) { }
|
||||
};
|
||||
|
||||
/* This shouldn't parse due to missing semicolon. */
|
||||
class _n_class2 : public n_class1 {
|
||||
void n_c2_method1(int a, int b) { }
|
||||
};
|
||||
|
||||
// Macros in the namespace
|
||||
#define NSMACRO 1
|
||||
|
||||
// Template in the namespace
|
||||
template<class T> T nsti1(const Foo& foo);
|
||||
template<> int nsti1<int>(const Foo& foo);
|
||||
|
||||
}
|
||||
|
||||
namespace namespace2 {
|
||||
|
||||
using namespace1::n_class1;
|
||||
|
||||
}
|
||||
|
||||
/* Initializers */
|
||||
void tinitializers1(): inita1(False),
|
||||
inita2(False)
|
||||
{
|
||||
inita1= 1;
|
||||
}
|
||||
|
||||
/* How about Extern C type things. */
|
||||
int funny_prototype(int ,int b,float c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int extern_c_1(int a, int b)
|
||||
{
|
||||
|
||||
funny_prototype(1,2,3.4);
|
||||
|
||||
printf("Moose", );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int extern_c_2(int a, int b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Some operator stuff
|
||||
class Action
|
||||
{
|
||||
// Problems!! operator() and operator[] can not be parsed with semantic
|
||||
// 1.4.2 but with latest c.by
|
||||
virtual void operator()(int i, char *p ) = 0;
|
||||
virtual String& operator[]() = 0;
|
||||
virtual void operator!() = 0;
|
||||
virtual void operator->() = 0;
|
||||
virtual T& operator+=();
|
||||
virtual T& operator*();
|
||||
virtual T& operator*=();
|
||||
};
|
||||
|
||||
// class with namespace qualified parents
|
||||
class Multiinherit : public virtual POA::Parent,
|
||||
public virtual POA::Parent1,
|
||||
Parent
|
||||
{
|
||||
private:
|
||||
int i;
|
||||
|
||||
public:
|
||||
Multiinherit();
|
||||
~Multiinherit();
|
||||
|
||||
// method with a list of qualified exceptions
|
||||
void* throwtest()
|
||||
throw(Exception0,
|
||||
Testnamespace::Exception1,
|
||||
Testnamespace::Excpetion2,
|
||||
Testnamespace::testnamespace1::Exception3);
|
||||
|
||||
};
|
||||
|
||||
void*
|
||||
Multiinherit::throwtest()
|
||||
throw (Exception0,
|
||||
Testnamespace::Exception1,
|
||||
Testnamespace::Excpetion2,
|
||||
Testnamespace::testnamespace1::Exception3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Jens Rock <jens.rock@asamnet.de>: Nested classes or structs defined
|
||||
// outside of the containing class/struct.
|
||||
class container
|
||||
{
|
||||
public:
|
||||
struct contained;
|
||||
container();
|
||||
~container();
|
||||
};
|
||||
|
||||
struct container::contained
|
||||
{
|
||||
public:
|
||||
contained();
|
||||
~contained();
|
||||
};
|
||||
|
||||
/*
|
||||
* Ok, how about some template stuff.
|
||||
*/
|
||||
template <class CT, class container = vector<CT> >
|
||||
const CT& max (const CT& a, const CT& b)
|
||||
{
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
// Arne Schmitz found this one
|
||||
std::vector<int> &a, &b, &c;
|
||||
|
||||
class TemplateUsingClass
|
||||
{
|
||||
typedef TestClassMap::iterator iterator;
|
||||
typedef map<long, long> TestClassMap;
|
||||
|
||||
// typedefs with const and volatile
|
||||
typedef const map<long, long> const_TestClassMap;
|
||||
typedef TestClassMap<string>::iterator volatile volatile_iterator;
|
||||
|
||||
map<int, int> mapclassvarthingy;
|
||||
};
|
||||
|
||||
template<class T> T ti1(const Foo& foo);
|
||||
template<> int ti1<int>(const Foo& foo);
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
// Now some namespace and related stuff
|
||||
// -----------------------------------
|
||||
|
||||
using CORBA::LEX::get_token;
|
||||
using Namespace1;
|
||||
|
||||
using namespace POA::std;
|
||||
using namespace Test;
|
||||
|
||||
|
||||
|
||||
namespace Parser
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Lexer::get_test;
|
||||
string str = "";
|
||||
}
|
||||
|
||||
namespace XXX
|
||||
{
|
||||
|
||||
class Foobar : public virtual POA::Parent,
|
||||
public virtual POA::Parent1,
|
||||
private POA::list<fact>,
|
||||
private map<string>
|
||||
{
|
||||
int i;
|
||||
list <shared_ptr<item> >::const_iterator l;
|
||||
public:
|
||||
|
||||
Foobar();
|
||||
~Foobar();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void test_function(int i);
|
||||
|
||||
};
|
||||
|
||||
// unnamed namespaces - even nested
|
||||
namespace
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using Lexer::get_test;
|
||||
string str = "";
|
||||
class FooClass
|
||||
{
|
||||
FooClass();
|
||||
};
|
||||
}
|
||||
|
||||
// some builtin types
|
||||
long long ll = 0;
|
||||
long double d = 0.0;
|
||||
unsigned test;
|
||||
unsigned long int **uli = 0;
|
||||
signed si = 0;
|
||||
signed short ss = 0;
|
||||
short int i = 0;
|
||||
long int li = 0;
|
||||
|
||||
// expressions with namespace/class-qualifyiers
|
||||
ORB_var cGlobalOrb = ORB::_nil();
|
||||
ORB_var1 cGlobalOrb1 = ORB::_test;
|
||||
|
||||
class Testclass
|
||||
{
|
||||
#define TEST 0
|
||||
ini i;
|
||||
|
||||
public:
|
||||
|
||||
Testclass();
|
||||
~Testclass();
|
||||
};
|
||||
|
||||
static void test_function(unsigned int i);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// outside method implementations which should be grouped to type Test
|
||||
XXX&
|
||||
Test::waiting()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Test::print()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// outside method implementations with namespaces which should be grouped to
|
||||
// their complete (incl. namespace) types
|
||||
void*
|
||||
Parser::XXX::Foobar::wait(int i, const char const * const * p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void*
|
||||
Namespace1::Test::wait1(int i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
Namespace1::Test::waiting(int i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// a class with some outside implementations which should all be grouped to
|
||||
// this class declaration
|
||||
class ClassWithExternals
|
||||
{
|
||||
private:
|
||||
int i;
|
||||
|
||||
public:
|
||||
ClassWithExternals();
|
||||
~ClassWithExternals();
|
||||
void non_nil();
|
||||
};
|
||||
|
||||
|
||||
// Foobar is not displayed; seems that semantic tries to add this to the class
|
||||
// Foobar but can not find/display it, because contained in the namespace above.
|
||||
void
|
||||
Foobar::non_nil()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// are correctly grouped to the ClassWithExternals class
|
||||
void
|
||||
ClassWithExternals::non_nil()
|
||||
{
|
||||
String s = "l<EFBFBD>dfjg dlfgkdlfkgjdl";
|
||||
return;
|
||||
}
|
||||
|
||||
ClassWithExternals::ClassWithExternals()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
ClassWithExternals::~ClassWithExternals()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
// Now some macro and define stuff
|
||||
// -------------------------------
|
||||
|
||||
#define TEST 0
|
||||
#define TEST1 "String"
|
||||
|
||||
// The first backslash makes this macro unmatched syntax with semantic 1.4.2!
|
||||
// With flexing \+newline as nothing all is working fine!
|
||||
#define MZK_ENTER(METHOD) \
|
||||
{ \
|
||||
CzkMethodLog lMethodLog(METHOD,"Framework");\
|
||||
}
|
||||
|
||||
#define ZK_ASSERTM(METHOD,ASSERTION,MESSAGE) \
|
||||
{ if(!(ASSERTION))\
|
||||
{\
|
||||
std::ostringstream lMesgStream; \
|
||||
lMesgStream << "Assertion failed: " \
|
||||
<< MESSAGE; \
|
||||
CzkLogManager::doLog(CzkLogManager::FATAL,"",METHOD, \
|
||||
"Assert",lMesgStream); \
|
||||
assert(ASSERTION);\
|
||||
}\
|
||||
}
|
||||
|
||||
// Test if not newline-backslashes are handled correctly
|
||||
string s = "My \"quoted\" string";
|
||||
|
||||
// parsed fine as macro
|
||||
#define FOO (arg) method(arg, "foo");
|
||||
|
||||
// With semantic 1.4.2 this parsed as macro BAR *and* function method.
|
||||
// With latest c.bnf at least one-liner macros can be parsed correctly.
|
||||
#define BAR (arg) CzkMessageLog method(arg, "bar");
|
||||
|
||||
// some const and volatile stuff
|
||||
char * p1 = "Hello"; // 1. variable Pointer, variable Data
|
||||
const char * p2 = "Hello"; // 2. variable pointer, constant data
|
||||
char * const p3 = "Hello"; // 3. constant pointer, variable data
|
||||
const char * const p4 = "Hello"; // 4. constant pointer, constant data
|
||||
|
||||
// Case 2 and 4 can exchange first "const" and "char"
|
||||
char const * p21 = "Hello"; // variable pointer, constant data
|
||||
char const * const p41 = "Hello"; // constant pointer, constant data
|
||||
|
||||
char volatile a = 0; // a volatile char
|
||||
void foo(bar const &arg); // a reference to a const bar
|
||||
int foobar(bar const * const p); // a const pointer to a const bar
|
||||
int foobar(bar const volatile * const p); // a const pointer to a const bar
|
||||
int foobar3(char* p); // a const pointer to a const bar
|
||||
|
||||
// Should not be parsed because this is invalid code
|
||||
int const & const r3 = i;
|
||||
|
||||
boolean i = 0;
|
||||
boolean & r1 = i;
|
||||
boolean const & r2 = i;
|
||||
|
||||
// const * sequences can be very long in C++ ;-)
|
||||
char const * const * const * const * ppp;
|
||||
|
||||
// complex function declarationen with named pointer-arguments
|
||||
const char** foobar1(volatile char const * const **p);
|
||||
const char** foobar11(volatile Test::Namespace::Char<char*> const * const **p);
|
||||
|
||||
// complex function declarationen with unnamed pointer-arguments
|
||||
const char* foobar2(const char***);
|
||||
const char* foobar21(const Test::Namespace::Char<char>***);
|
||||
|
||||
// string literal parsing even with wchar_t
|
||||
char const *p = "string1";
|
||||
char const *q = "string1" "str\"ing2" "string3";
|
||||
wchar_t testc = L'a';
|
||||
|
||||
wchar_t const *wp = L"string with a \" in it";
|
||||
wchar_t const *wq = L"string \n\t\"test" L"string2";
|
||||
wchar_t const *wr = L"string L";
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- http://blog.flexexamples.com/2007/12/13/rounding-numbers-in-flex-using-the-numberformatter-class/ -->
|
||||
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
|
||||
layout="vertical"
|
||||
verticalAlign="middle"
|
||||
backgroundColor="white">
|
||||
|
||||
<mx:Script>
|
||||
<![CDATA[
|
||||
import mx.collections.ArrayCollection;
|
||||
import mx.formatters.NumberBaseRoundType;
|
||||
|
||||
private function button_click(evt:MouseEvent):void {
|
||||
textInput.errorString = "";
|
||||
numberFormatter.format(textInput.text);
|
||||
if (numberFormatter.error) {
|
||||
textInput.errorString = numberFormatter.error;
|
||||
}
|
||||
|
||||
arrColl = new ArrayCollection();
|
||||
|
||||
numberFormatter.rounding = NumberBaseRoundType.NEAREST;
|
||||
arrColl.addItem({type:numberFormatter.rounding,
|
||||
value:numberFormatter.format(textInput.text)});
|
||||
|
||||
numberFormatter.rounding = NumberBaseRoundType.UP;
|
||||
arrColl.addItem({type:numberFormatter.rounding,
|
||||
value:numberFormatter.format(textInput.text)});
|
||||
|
||||
numberFormatter.rounding = NumberBaseRoundType.DOWN;
|
||||
arrColl.addItem({type:numberFormatter.rounding,
|
||||
value:numberFormatter.format(textInput.text)});
|
||||
|
||||
numberFormatter.rounding = NumberBaseRoundType.NONE;
|
||||
arrColl.addItem({type:numberFormatter.rounding,
|
||||
value:numberFormatter.format(textInput.text)});
|
||||
}
|
||||
]]>
|
||||
</mx:Script>
|
||||
|
||||
<mx:ArrayCollection id="arrColl" />
|
||||
|
||||
<mx:NumberFormatter id="numberFormatter"
|
||||
precision="2"
|
||||
rounding="up" />
|
||||
|
||||
<mx:ApplicationControlBar dock="true">
|
||||
<mx:Form styleName="plain">
|
||||
<mx:FormItem label="number:"
|
||||
direction="horizontal">
|
||||
<mx:TextInput id="textInput"
|
||||
text="2.0499"
|
||||
restrict="[0-9.-]"
|
||||
maxChars="6" />
|
||||
<mx:Button label="format"
|
||||
click="button_click(event);" />
|
||||
</mx:FormItem>
|
||||
</mx:Form>
|
||||
</mx:ApplicationControlBar>
|
||||
|
||||
<mx:DataGrid id="dataGrid"
|
||||
dataProvider="{arrColl}"
|
||||
rowCount="4" />
|
||||
|
||||
</mx:Application>
|
||||
@@ -1,98 +0,0 @@
|
||||
(* $Id: fifteen.ml,v 1.8 2001/09/06 08:47:55 garrigue Exp $ *)
|
||||
|
||||
open StdLabels
|
||||
open Gaux
|
||||
open Gtk
|
||||
open GObj
|
||||
open GMain
|
||||
|
||||
class position ~init_x ~init_y ~min_x ~min_y ~max_x ~max_y = object
|
||||
val mutable x = init_x
|
||||
val mutable y = init_y
|
||||
method current = (x, y)
|
||||
method up () = if y > min_y then y <- y-1 else (); (x, y)
|
||||
method down () = if y < max_y then y <- y+1 else (); (x, y)
|
||||
method left () = if x > min_x then x <- x-1 else (); (x, y)
|
||||
method right () = if x < max_x then x <- x+1 else (); (x, y)
|
||||
end
|
||||
|
||||
let game_init () = (* generate initial puzzle state *)
|
||||
let rec game_aux acc rest n_invert =
|
||||
let len = List.length rest in
|
||||
if len=0 then
|
||||
if n_invert mod 2 = 0 then
|
||||
acc (* to be solvable, n_invert must be even *)
|
||||
else
|
||||
(List.hd (List.tl acc))::(List.hd acc)::(List.tl (List.tl acc))
|
||||
else begin
|
||||
let rec extract n xs =
|
||||
if (n=0) then (List.hd xs, List.tl xs)
|
||||
else
|
||||
let (ans, ys) = extract (n-1) (List.tl xs) in
|
||||
(ans, List.hd xs :: ys) in
|
||||
let ran = Random.int len in
|
||||
let (elm, rest1) = extract ran rest in
|
||||
let rec count p xs = match xs with
|
||||
[] -> 0
|
||||
| y :: ys -> let acc = count p ys in
|
||||
if p y then 1+acc else acc
|
||||
in
|
||||
let new_n_invert = count (fun x -> elm > x) acc in
|
||||
game_aux (elm :: acc) rest1 (n_invert+new_n_invert)
|
||||
end in
|
||||
let rec from n = if n=0 then [] else n :: from (n-1) in
|
||||
game_aux [] (from 15) 0
|
||||
|
||||
let _ = Random.init (int_of_float (Sys.time () *. 1000.))
|
||||
let window = GWindow.window ()
|
||||
let _ = window#connect#destroy ~callback:GMain.Main.quit
|
||||
|
||||
let tbl = GPack.table ~rows:4 ~columns:4 ~homogeneous:true ~packing:window#add ()
|
||||
let dummy = GMisc.label ~text:"" ~packing:(tbl#attach ~left:3 ~top:3) ()
|
||||
let arr = Array.create_matrix ~dimx:4 ~dimy:4 dummy
|
||||
let init = game_init ()
|
||||
let _ =
|
||||
for i = 0 to 15 do
|
||||
let j = i mod 4 in
|
||||
let k = i/4 in
|
||||
let frame =
|
||||
GBin.frame ~shadow_type:`OUT ~width:32 ~height:32
|
||||
~packing:(tbl#attach ~left:j ~top:k) () in
|
||||
if i < 15 then
|
||||
arr.(j).(k) <-
|
||||
GMisc.label ~text:(string_of_int (List.nth init i))
|
||||
~packing:frame#add ()
|
||||
done
|
||||
let pos = new position ~init_x:3 ~init_y:3 ~min_x:0 ~min_y:0 ~max_x:3 ~max_y:3
|
||||
|
||||
open GdkKeysyms
|
||||
|
||||
let _ =
|
||||
window#event#connect#key_press ~callback:
|
||||
begin fun ev ->
|
||||
let (x0, y0) = pos#current in
|
||||
let wid0 = arr.(x0).(y0) in
|
||||
let key = GdkEvent.Key.keyval ev in
|
||||
if key = _q || key = _Escape then (Main.quit (); exit 0) else
|
||||
let (x1, y1) =
|
||||
if key = _h || key = _Left then
|
||||
pos#right ()
|
||||
else if key = _j || key = _Down then
|
||||
pos#up ()
|
||||
else if key = _k || key = _Up then
|
||||
pos#down ()
|
||||
else if key = _l || key = _Right then
|
||||
pos#left ()
|
||||
else (x0, y0)
|
||||
in
|
||||
let wid1 = arr.(x1).(y1) in
|
||||
wid0#set_text (wid1#text);
|
||||
wid1#set_text "";
|
||||
true
|
||||
end
|
||||
|
||||
let main () =
|
||||
window#show ();
|
||||
Main.main ()
|
||||
|
||||
let _ = main ()
|
||||
@@ -1,153 +0,0 @@
|
||||
(************************************************************************)
|
||||
(* v * The Coq Proof Assistant / The Coq Development Team *)
|
||||
(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
|
||||
(* \VV/ **************************************************************)
|
||||
(* // * This file is distributed under the terms of the *)
|
||||
(* * GNU Lesser General Public License Version 2.1 *)
|
||||
(************************************************************************)
|
||||
|
||||
(* $Id$ *)
|
||||
|
||||
(*s Heaps *)
|
||||
|
||||
module type Ordered = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
module type S =sig
|
||||
|
||||
(* Type of functional heaps *)
|
||||
type t
|
||||
|
||||
(* Type of elements *)
|
||||
type elt
|
||||
|
||||
(* The empty heap *)
|
||||
val empty : t
|
||||
|
||||
(* [add x h] returns a new heap containing the elements of [h], plus [x];
|
||||
complexity $O(log(n))$ *)
|
||||
val add : elt -> t -> t
|
||||
|
||||
(* [maximum h] returns the maximum element of [h]; raises [EmptyHeap]
|
||||
when [h] is empty; complexity $O(1)$ *)
|
||||
val maximum : t -> elt
|
||||
|
||||
(* [remove h] returns a new heap containing the elements of [h], except
|
||||
the maximum of [h]; raises [EmptyHeap] when [h] is empty;
|
||||
complexity $O(log(n))$ *)
|
||||
val remove : t -> t
|
||||
|
||||
(* usual iterators and combinators; elements are presented in
|
||||
arbitrary order *)
|
||||
val iter : (elt -> unit) -> t -> unit
|
||||
|
||||
val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
|
||||
|
||||
end
|
||||
|
||||
exception EmptyHeap
|
||||
|
||||
(*s Functional implementation *)
|
||||
|
||||
module Functional(X : Ordered) = struct
|
||||
|
||||
(* Heaps are encoded as complete binary trees, i.e., binary trees
|
||||
which are full expect, may be, on the bottom level where it is filled
|
||||
from the left.
|
||||
These trees also enjoy the heap property, namely the value of any node
|
||||
is greater or equal than those of its left and right subtrees.
|
||||
|
||||
There are 4 kinds of complete binary trees, denoted by 4 constructors:
|
||||
[FFF] for a full binary tree (and thus 2 full subtrees);
|
||||
[PPF] for a partial tree with a partial left subtree and a full
|
||||
right subtree;
|
||||
[PFF] for a partial tree with a full left subtree and a full right subtree
|
||||
(but of different heights);
|
||||
and [PFP] for a partial tree with a full left subtree and a partial
|
||||
right subtree. *)
|
||||
|
||||
type t =
|
||||
| Empty
|
||||
| FFF of t * X.t * t (* full (full, full) *)
|
||||
| PPF of t * X.t * t (* partial (partial, full) *)
|
||||
| PFF of t * X.t * t (* partial (full, full) *)
|
||||
| PFP of t * X.t * t (* partial (full, partial) *)
|
||||
|
||||
type elt = X.t
|
||||
|
||||
let empty = Empty
|
||||
|
||||
(* smart constructors for insertion *)
|
||||
let p_f l x r = match l with
|
||||
| Empty | FFF _ -> PFF (l, x, r)
|
||||
| _ -> PPF (l, x, r)
|
||||
|
||||
let pf_ l x = function
|
||||
| Empty | FFF _ as r -> FFF (l, x, r)
|
||||
| r -> PFP (l, x, r)
|
||||
|
||||
let rec add x = function
|
||||
| Empty ->
|
||||
FFF (Empty, x, Empty)
|
||||
(* insertion to the left *)
|
||||
| FFF (l, y, r) | PPF (l, y, r) ->
|
||||
if X.compare x y > 0 then p_f (add y l) x r else p_f (add x l) y r
|
||||
(* insertion to the right *)
|
||||
| PFF (l, y, r) | PFP (l, y, r) ->
|
||||
if X.compare x y > 0 then pf_ l x (add y r) else pf_ l y (add x r)
|
||||
|
||||
let maximum = function
|
||||
| Empty -> raise EmptyHeap
|
||||
| FFF (_, x, _) | PPF (_, x, _) | PFF (_, x, _) | PFP (_, x, _) -> x
|
||||
|
||||
(* smart constructors for removal; note that they are different
|
||||
from the ones for insertion! *)
|
||||
let p_f l x r = match l with
|
||||
| Empty | FFF _ -> FFF (l, x, r)
|
||||
| _ -> PPF (l, x, r)
|
||||
|
||||
let pf_ l x = function
|
||||
| Empty | FFF _ as r -> PFF (l, x, r)
|
||||
| r -> PFP (l, x, r)
|
||||
|
||||
let rec remove = function
|
||||
| Empty ->
|
||||
raise EmptyHeap
|
||||
| FFF (Empty, _, Empty) ->
|
||||
Empty
|
||||
| PFF (l, _, Empty) ->
|
||||
l
|
||||
(* remove on the left *)
|
||||
| PPF (l, x, r) | PFF (l, x, r) ->
|
||||
let xl = maximum l in
|
||||
let xr = maximum r in
|
||||
let l' = remove l in
|
||||
if X.compare xl xr >= 0 then
|
||||
p_f l' xl r
|
||||
else
|
||||
p_f l' xr (add xl (remove r))
|
||||
(* remove on the right *)
|
||||
| FFF (l, x, r) | PFP (l, x, r) ->
|
||||
let xl = maximum l in
|
||||
let xr = maximum r in
|
||||
let r' = remove r in
|
||||
if X.compare xl xr > 0 then
|
||||
pf_ (add xr (remove l)) xl r'
|
||||
else
|
||||
pf_ l xr r'
|
||||
|
||||
let rec iter f = function
|
||||
| Empty ->
|
||||
()
|
||||
| FFF (l, x, r) | PPF (l, x, r) | PFF (l, x, r) | PFP (l, x, r) ->
|
||||
iter f l; f x; iter f r
|
||||
|
||||
let rec fold f h x0 = match h with
|
||||
| Empty ->
|
||||
x0
|
||||
| FFF (l, x, r) | PPF (l, x, r) | PFF (l, x, r) | PFP (l, x, r) ->
|
||||
fold f l (fold f r (f x x0))
|
||||
|
||||
end
|
||||
@@ -1,294 +0,0 @@
|
||||
(* ========================================================================= *)
|
||||
(* Knuth-Bendix completion done by HOL inference. John Harrison 2005 *)
|
||||
(* *)
|
||||
(* This was written by fairly mechanical modification of the code at *)
|
||||
(* *)
|
||||
(* http://www.cl.cam.ac.uk/users/jrh/atp/order.ml *)
|
||||
(* http://www.cl.cam.ac.uk/users/jrh/atp/completion.ml *)
|
||||
(* *)
|
||||
(* for HOL's slightly different term structure, with ad hoc term *)
|
||||
(* manipulations replaced by inference on equational theorems. We also have *)
|
||||
(* the optimization of throwing left-reducible rules back into the set of *)
|
||||
(* critical pairs. However, we don't prioritize smaller critical pairs or *)
|
||||
(* anything like that; this is still a very naive implementation. *)
|
||||
(* *)
|
||||
(* For something very similar done 15 years ago, see Konrad Slind's Master's *)
|
||||
(* thesis: "An Implementation of Higher Order Logic", U Calgary 1991. *)
|
||||
(* ========================================================================= *)
|
||||
|
||||
let is_realvar w x = is_var x & not(mem x w);;
|
||||
|
||||
let rec real_strip w tm =
|
||||
if mem tm w then tm,[] else
|
||||
let l,r = dest_comb tm in
|
||||
let f,args = real_strip w l in f,args@[r];;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Construct a weighting function. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let weight lis (f,n) (g,m) =
|
||||
let i = index f lis and j = index g lis in
|
||||
i > j or i = j & n > m;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Generic lexicographic ordering function. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let rec lexord ord l1 l2 =
|
||||
match (l1,l2) with
|
||||
(h1::t1,h2::t2) -> if ord h1 h2 then length t1 = length t2
|
||||
else h1 = h2 & lexord ord t1 t2
|
||||
| _ -> false;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Lexicographic path ordering. Note that we also use the weights *)
|
||||
(* to define the set of constants, so they don't literally have to be *)
|
||||
(* constants in the HOL sense. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let rec lpo_gt w s t =
|
||||
if is_realvar w t then not(s = t) & mem t (frees s)
|
||||
else if is_realvar w s or is_abs s or is_abs t then false else
|
||||
let f,fargs = real_strip w s and g,gargs = real_strip w t in
|
||||
exists (fun si -> lpo_ge w si t) fargs or
|
||||
forall (lpo_gt w s) gargs &
|
||||
(f = g & lexord (lpo_gt w) fargs gargs or
|
||||
weight w (f,length fargs) (g,length gargs))
|
||||
and lpo_ge w s t = (s = t) or lpo_gt w s t;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Unification. Again we have the weights "w" fixing the set of constants. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let rec istriv w env x t =
|
||||
if is_realvar w t then t = x or defined env t & istriv w env x (apply env t)
|
||||
else if is_const t then false else
|
||||
let f,args = strip_comb t in
|
||||
exists (istriv w env x) args & failwith "cyclic";;
|
||||
|
||||
let rec unify w env tp =
|
||||
match tp with
|
||||
((Var(_,_) as x),t) | (t,(Var(_,_) as x)) when not(mem x w) ->
|
||||
if defined env x then unify w env (apply env x,t)
|
||||
else if istriv w env x t then env else (x|->t) env
|
||||
| (Comb(f,x),Comb(g,y)) -> unify w (unify w env (x,y)) (f,g)
|
||||
| (s,t) -> if s = t then env else failwith "unify: not unifiable";;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Full unification, unravelling graph into HOL-style instantiation list. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let fullunify w (s,t) =
|
||||
let env = unify w undefined (s,t) in
|
||||
let th = map (fun (x,t) -> (t,x)) (graph env) in
|
||||
let rec subs t =
|
||||
let t' = vsubst th t in
|
||||
if t' = t then t else subs t' in
|
||||
map (fun (t,x) -> (subs t,x)) th;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Construct "overlaps": ways of rewriting subterms using unification. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let LIST_MK_COMB f ths = rev_itlist (fun s t -> MK_COMB(t,s)) ths (REFL f);;
|
||||
|
||||
let rec listcases fn rfn lis acc =
|
||||
match lis with
|
||||
[] -> acc
|
||||
| h::t -> fn h (fun i h' -> rfn i (h'::map REFL t)) @
|
||||
listcases fn (fun i t' -> rfn i (REFL h::t')) t acc;;
|
||||
|
||||
let rec overlaps w th tm rfn =
|
||||
let l,r = dest_eq(concl th) in
|
||||
if not (is_comb tm) then [] else
|
||||
let f,args = strip_comb tm in
|
||||
listcases (overlaps w th) (fun i a -> rfn i (LIST_MK_COMB f a)) args
|
||||
(try [rfn (fullunify w (l,tm)) th] with Failure _ -> []);;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Rename variables canonically to avoid clashes or remove redundancy. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let fixvariables s th =
|
||||
let fvs = subtract (frees(concl th)) (freesl(hyp th)) in
|
||||
let gvs = map2 (fun v n -> mk_var(s^string_of_int n,type_of v))
|
||||
fvs (1--(length fvs)) in
|
||||
INST (zip gvs fvs) th;;
|
||||
|
||||
let renamepair (th1,th2) = fixvariables "x" th1,fixvariables "y" th2;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Find all critical pairs. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let crit1 w eq1 eq2 =
|
||||
let l1,r1 = dest_eq(concl eq1)
|
||||
and l2,r2 = dest_eq(concl eq2) in
|
||||
overlaps w eq1 l2 (fun i th -> TRANS (SYM(INST i th)) (INST i eq2));;
|
||||
|
||||
let thm_union l1 l2 =
|
||||
itlist (fun th ths -> let th' = fixvariables "x" th in
|
||||
let tm = concl th' in
|
||||
if exists (fun th'' -> concl th'' = tm) ths then ths
|
||||
else th'::ths)
|
||||
l1 l2;;
|
||||
|
||||
let critical_pairs w tha thb =
|
||||
let th1,th2 = renamepair (tha,thb) in
|
||||
if concl th1 = concl th2 then crit1 w th1 th2 else
|
||||
filter (fun th -> let l,r = dest_eq(concl th) in l <> r)
|
||||
(thm_union (crit1 w th1 th2) (thm_union (crit1 w th2 th1) []));;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Normalize an equation and try to orient it. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let normalize_and_orient w eqs th =
|
||||
let th' = GEN_REWRITE_RULE TOP_DEPTH_CONV eqs th in
|
||||
let s',t' = dest_eq(concl th') in
|
||||
if lpo_ge w s' t' then th' else if lpo_ge w t' s' then SYM th'
|
||||
else failwith "Can't orient equation";;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Print out status report to reduce user boredom. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let status(eqs,crs) eqs0 =
|
||||
if eqs = eqs0 & (length crs) mod 1000 <> 0 then () else
|
||||
(print_string(string_of_int(length eqs)^" equations and "^
|
||||
string_of_int(length crs)^" pending critical pairs");
|
||||
print_newline());;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Basic completion, throwing back left-reducible rules. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let left_reducible eqs eq =
|
||||
can (CHANGED_CONV(GEN_REWRITE_CONV (LAND_CONV o ONCE_DEPTH_CONV) eqs))
|
||||
(concl eq);;
|
||||
|
||||
let rec complete w (eqs,crits) =
|
||||
match crits with
|
||||
(eq::ocrits) ->
|
||||
let trip =
|
||||
try let eq' = normalize_and_orient w eqs eq in
|
||||
let s',t' = dest_eq(concl eq') in
|
||||
if s' = t' then (eqs,ocrits) else
|
||||
let crits',eqs' = partition(left_reducible [eq']) eqs in
|
||||
let eqs'' = eq'::eqs' in
|
||||
eqs'',
|
||||
ocrits @ crits' @ itlist ((@) o critical_pairs w eq') eqs'' []
|
||||
with Failure _ ->
|
||||
if exists (can (normalize_and_orient w eqs)) ocrits
|
||||
then (eqs,ocrits@[eq])
|
||||
else failwith "complete: no orientable equations" in
|
||||
status trip eqs; complete w trip
|
||||
| [] -> eqs;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Overall completion. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let complete_equations wts eqs =
|
||||
let eqs' = map (normalize_and_orient wts []) eqs in
|
||||
complete wts ([],eqs');;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Knuth-Bendix example 4: the inverse property. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
complete_equations [`1`; `(*):num->num->num`; `i:num->num`]
|
||||
[SPEC_ALL(ASSUME `!a b. i(a) * a * b = b`)];;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Knuth-Bendix example 6: central groupoids. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
complete_equations [`(*):num->num->num`]
|
||||
[SPEC_ALL(ASSUME `!a b c. (a * b) * (b * c) = b`)];;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Knuth-Bendix example 9: cancellation law. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
complete_equations
|
||||
[`1`; `( * ):num->num->num`; `(+):num->num->num`; `(-):num->num->num`]
|
||||
(map SPEC_ALL (CONJUNCTS (ASSUME
|
||||
`(!a b:num. a - a * b = b) /\
|
||||
(!a b:num. a * b - b = a) /\
|
||||
(!a. a * 1 = a) /\
|
||||
(!a. 1 * a = a)`)));;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Another example: pure congruence closure (no variables). *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
complete_equations [`c:A`; `f:A->A`]
|
||||
(map SPEC_ALL (CONJUNCTS (ASSUME
|
||||
`((f(f(f(f(f c))))) = c:A) /\ (f(f(f c)) = c)`)));;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Knuth-Bendix example 1: group theory. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let eqs = map SPEC_ALL (CONJUNCTS (ASSUME
|
||||
`(!x. 1 * x = x) /\ (!x. i(x) * x = 1) /\
|
||||
(!x y z. (x * y) * z = x * y * z)`));;
|
||||
|
||||
complete_equations [`1`; `(*):num->num->num`; `i:num->num`] eqs;;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Near-rings (from Aichinger's Diplomarbeit). *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let eqs = map SPEC_ALL (CONJUNCTS (ASSUME
|
||||
`(!x. 0 + x = x) /\
|
||||
(!x. neg x + x = 0) /\
|
||||
(!x y z. (x + y) + z = x + y + z) /\
|
||||
(!x y z. (x * y) * z = x * y * z) /\
|
||||
(!x y z. (x + y) * z = (x * z) + (y * z))`));;
|
||||
|
||||
let nreqs =
|
||||
complete_equations
|
||||
[`0`; `(+):num->num->num`; `neg:num->num`; `( * ):num->num->num`] eqs;;
|
||||
|
||||
(*** This weighting also works OK, though the system is a bit bigger
|
||||
|
||||
let nreqs =
|
||||
complete_equations
|
||||
[`0`; `(+):num->num->num`; `( * ):num->num->num`; `INV`] eqs;;
|
||||
|
||||
****)
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* A "completion" tactic. *)
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
|
||||
let COMPLETE_TAC w th =
|
||||
let eqs = map SPEC_ALL (CONJUNCTS(SPEC_ALL th)) in
|
||||
let eqs' = complete_equations w eqs in
|
||||
MAP_EVERY (ASSUME_TAC o GEN_ALL) eqs';;
|
||||
|
||||
(* ------------------------------------------------------------------------- *)
|
||||
(* Solve example problems in gr *)
|
||||
|
||||
g `(!x. 1 * x = x) /\
|
||||
(!x. i(x) * x = 1) /\
|
||||
(!x y z. (x * y) * z = x * y * z)
|
||||
==> !x y. i(y) * i(i(i(x * i(y)))) * x = 1`;;
|
||||
|
||||
e (DISCH_THEN(COMPLETE_TAC [`1`; `(*):num->num->num`; `i:num->num`]));;
|
||||
e (ASM_REWRITE_TAC[]);;
|
||||
|
||||
g `(!x. 0 + x = x) /\
|
||||
(!x. neg x + x = 0) /\
|
||||
(!x y z. (x + y) + z = x + y + z) /\
|
||||
(!x y z. (x * y) * z = x * y * z) /\
|
||||
(!x y z. (x + y) * z = (x * z) + (y * z))
|
||||
==> (neg 0 * (x * y + z + neg(neg(w + z))) + neg(neg b + neg a) =
|
||||
a + b)`;;
|
||||
|
||||
e (DISCH_THEN(COMPLETE_TAC
|
||||
[`0`; `(+):num->num->num`; `neg:num->num`; `( * ):num->num->num`]));;
|
||||
e (ASM_REWRITE_TAC[]);;
|
||||
@@ -1,82 +0,0 @@
|
||||
(*
|
||||
* Xml Light, an small Xml parser/printer with DTD support.
|
||||
* Copyright (C) 2003 Nicolas Cannasse (ncannasse@motion-twin.com)
|
||||
*
|
||||
* 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 has the special exception on linking described in file
|
||||
* README.
|
||||
*
|
||||
* 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 Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*)
|
||||
|
||||
(** Xml Light Parser
|
||||
|
||||
While basic parsing functions can be used in the {!Xml} module, this module
|
||||
is providing a way to create, configure and run an Xml parser.
|
||||
|
||||
*)
|
||||
|
||||
(** Abstract type for an Xml parser. *)
|
||||
type t
|
||||
|
||||
(** Several kind of resources can contain Xml documents. *)
|
||||
type source =
|
||||
| SFile of string
|
||||
| SChannel of in_channel
|
||||
| SString of string
|
||||
| SLexbuf of Lexing.lexbuf
|
||||
|
||||
(** This function returns a new parser with default options. *)
|
||||
val make : unit -> t
|
||||
|
||||
(** This function enable or disable automatic DTD proving with the parser.
|
||||
Note that Xml documents having no reference to a DTD are never proved
|
||||
when parsed (but you can prove them later using the {!Dtd} module
|
||||
{i (by default, prove is true)}. *)
|
||||
val prove : t -> bool -> unit
|
||||
|
||||
(** When parsing an Xml document from a file using the {!Xml.parse_file}
|
||||
function, the DTD file if declared by the Xml document has to be in the
|
||||
same directory as the xml file. When using other parsing functions,
|
||||
such as on a string or on a channel, the parser will raise everytime
|
||||
{!Xml.File_not_found} if a DTD file is needed and prove enabled. To enable
|
||||
the DTD loading of the file, the user have to configure the Xml parser
|
||||
with a [resolve] function which is taking as argument the DTD filename and
|
||||
is returning a checked DTD. The user can then implement any kind of DTD
|
||||
loading strategy, and can use the {!Dtd} module functions to parse and check
|
||||
the DTD file {i (by default, the resolve function is raising}
|
||||
{!Xml.File_not_found}). *)
|
||||
val resolve : t -> (string -> Dtd.checked) -> unit
|
||||
|
||||
(** When a Xml document is parsed, the parser will check that the end of the
|
||||
document is reached, so for example parsing ["<A/><B/>"] will fail instead
|
||||
of returning only the A element. You can turn off this check by setting
|
||||
[check_eof] to [false] {i (by default, check_eof is true)}. *)
|
||||
val check_eof : t -> bool -> unit
|
||||
|
||||
(** Once the parser is configurated, you can run the parser on a any kind
|
||||
of xml document source to parse its contents into an Xml data structure. *)
|
||||
val parse : t -> source -> Xml.xml
|
||||
|
||||
(** When several PCData elements are separed by a \n (or \r\n), you can
|
||||
either split the PCData in two distincts PCData or merge them with \n
|
||||
as seperator into one PCData. The default behavior is to concat the
|
||||
PCData, but this can be changed for a given parser with this flag. *)
|
||||
val concat_pcdata : t -> bool -> unit
|
||||
|
||||
(**/**)
|
||||
|
||||
(* internal usage only... *)
|
||||
val _raises : (Xml.error_msg -> Lexing.lexbuf -> exn) -> (string -> exn) -> (Dtd.parse_error_msg -> Lexing.lexbuf -> exn) -> unit
|
||||
@@ -1,721 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DomCrawler;
|
||||
|
||||
use Symfony\Component\CssSelector\CssSelector;
|
||||
|
||||
/**
|
||||
* Crawler eases navigation of a list of \DOMNode objects.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Crawler extends \SplObjectStorage
|
||||
{
|
||||
/**
|
||||
* @var string The current URI or the base href value
|
||||
*/
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param mixed $node A Node to use as the base for the crawling
|
||||
* @param string $uri The current URI or the base href value
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($node = null, $uri = null)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
|
||||
$this->add($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the nodes.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->removeAll($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a node to the current list of nodes.
|
||||
*
|
||||
* This method uses the appropriate specialized add*() method based
|
||||
* on the type of the argument.
|
||||
*
|
||||
* @param null|\DOMNodeList|array|\DOMNode $node A node
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function add($node)
|
||||
{
|
||||
if ($node instanceof \DOMNodeList) {
|
||||
$this->addNodeList($node);
|
||||
} elseif (is_array($node)) {
|
||||
$this->addNodes($node);
|
||||
} elseif (is_string($node)) {
|
||||
$this->addContent($node);
|
||||
} elseif (is_object($node)) {
|
||||
$this->addNode($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds HTML/XML content.
|
||||
*
|
||||
* @param string $content A string to parse as HTML/XML
|
||||
* @param null|string $type The content type of the string
|
||||
*
|
||||
* @return null|void
|
||||
*/
|
||||
public function addContent($content, $type = null)
|
||||
{
|
||||
if (empty($type)) {
|
||||
$type = 'text/html';
|
||||
}
|
||||
|
||||
// DOM only for HTML/XML content
|
||||
if (!preg_match('/(x|ht)ml/i', $type, $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$charset = 'ISO-8859-1';
|
||||
if (false !== $pos = strpos($type, 'charset=')) {
|
||||
$charset = substr($type, $pos + 8);
|
||||
if (false !== $pos = strpos($charset, ';')) {
|
||||
$charset = substr($charset, 0, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
if ('x' === $matches[1]) {
|
||||
$this->addXmlContent($content, $charset);
|
||||
} else {
|
||||
$this->addHtmlContent($content, $charset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an HTML content to the list of nodes.
|
||||
*
|
||||
* The libxml errors are disabled when the content is parsed.
|
||||
*
|
||||
* If you want to get parsing errors, be sure to enable
|
||||
* internal errors via libxml_use_internal_errors(true)
|
||||
* and then, get the errors via libxml_get_errors(). Be
|
||||
* sure to clear errors with libxml_clear_errors() afterward.
|
||||
*
|
||||
* @param string $content The HTML content
|
||||
* @param string $charset The charset
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addHtmlContent($content, $charset = 'UTF-8')
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', $charset);
|
||||
$dom->validateOnParse = true;
|
||||
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
$content = mb_convert_encoding($content, 'HTML-ENTITIES', $charset);
|
||||
}
|
||||
|
||||
$current = libxml_use_internal_errors(true);
|
||||
@$dom->loadHTML($content);
|
||||
libxml_use_internal_errors($current);
|
||||
|
||||
$this->addDocument($dom);
|
||||
|
||||
$base = $this->filterXPath('descendant-or-self::base')->extract(array('href'));
|
||||
|
||||
if (count($base)) {
|
||||
$this->uri = current($base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an XML content to the list of nodes.
|
||||
*
|
||||
* The libxml errors are disabled when the content is parsed.
|
||||
*
|
||||
* If you want to get parsing errors, be sure to enable
|
||||
* internal errors via libxml_use_internal_errors(true)
|
||||
* and then, get the errors via libxml_get_errors(). Be
|
||||
* sure to clear errors with libxml_clear_errors() afterward.
|
||||
*
|
||||
* @param string $content The XML content
|
||||
* @param string $charset The charset
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addXmlContent($content, $charset = 'UTF-8')
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', $charset);
|
||||
$dom->validateOnParse = true;
|
||||
|
||||
// remove the default namespace to make XPath expressions simpler
|
||||
$current = libxml_use_internal_errors(true);
|
||||
@$dom->loadXML(str_replace('xmlns', 'ns', $content));
|
||||
libxml_use_internal_errors($current);
|
||||
|
||||
$this->addDocument($dom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a \DOMDocument to the list of nodes.
|
||||
*
|
||||
* @param \DOMDocument $dom A \DOMDocument instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addDocument(\DOMDocument $dom)
|
||||
{
|
||||
if ($dom->documentElement) {
|
||||
$this->addNode($dom->documentElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a \DOMNodeList to the list of nodes.
|
||||
*
|
||||
* @param \DOMNodeList $nodes A \DOMNodeList instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addNodeList(\DOMNodeList $nodes)
|
||||
{
|
||||
foreach ($nodes as $node) {
|
||||
$this->addNode($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an array of \DOMNode instances to the list of nodes.
|
||||
*
|
||||
* @param array $nodes An array of \DOMNode instances
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addNodes(array $nodes)
|
||||
{
|
||||
foreach ($nodes as $node) {
|
||||
$this->add($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a \DOMNode instance to the list of nodes.
|
||||
*
|
||||
* @param \DOMNode $node A \DOMNode instance
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function addNode(\DOMNode $node)
|
||||
{
|
||||
if ($node instanceof \DOMDocument) {
|
||||
$this->attach($node->documentElement);
|
||||
} else {
|
||||
$this->attach($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a node given its position in the node list.
|
||||
*
|
||||
* @param integer $position The position
|
||||
*
|
||||
* @return Crawler A new instance of the Crawler with the selected node, or an empty Crawler if it does not exist.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function eq($position)
|
||||
{
|
||||
foreach ($this as $i => $node) {
|
||||
if ($i == $position) {
|
||||
return new static($node, $this->uri);
|
||||
}
|
||||
}
|
||||
|
||||
return new static(null, $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an anonymous function on each node of the list.
|
||||
*
|
||||
* The anonymous function receives the position and the node as arguments.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $crawler->filter('h1')->each(function ($node, $i)
|
||||
* {
|
||||
* return $node->nodeValue;
|
||||
* });
|
||||
*
|
||||
* @param \Closure $closure An anonymous function
|
||||
*
|
||||
* @return array An array of values returned by the anonymous function
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function each(\Closure $closure)
|
||||
{
|
||||
$data = array();
|
||||
foreach ($this as $i => $node) {
|
||||
$data[] = $closure($node, $i);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the list of nodes by calling an anonymous function.
|
||||
*
|
||||
* To remove a node from the list, the anonymous function must return false.
|
||||
*
|
||||
* @param \Closure $closure An anonymous function
|
||||
*
|
||||
* @return Crawler A Crawler instance with the selected nodes.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function reduce(\Closure $closure)
|
||||
{
|
||||
$nodes = array();
|
||||
foreach ($this as $i => $node) {
|
||||
if (false !== $closure($node, $i)) {
|
||||
$nodes[] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
return new static($nodes, $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first node of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the first selected node
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function first()
|
||||
{
|
||||
return $this->eq(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last node of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the last selected node
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function last()
|
||||
{
|
||||
return $this->eq(count($this) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the siblings nodes of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the sibling nodes
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function siblings()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return new static($this->sibling($this->getNode(0)->parentNode->firstChild), $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next siblings nodes of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the next sibling nodes
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function nextAll()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return new static($this->sibling($this->getNode(0)), $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previous sibling nodes of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the previous sibling nodes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function previousAll()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return new static($this->sibling($this->getNode(0), 'previousSibling'), $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parents nodes of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the parents nodes of the current selection
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function parents()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
$node = $this->getNode(0);
|
||||
$nodes = array();
|
||||
|
||||
while ($node = $node->parentNode) {
|
||||
if (1 === $node->nodeType && '_root' !== $node->nodeName) {
|
||||
$nodes[] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
return new static($nodes, $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the children nodes of the current selection
|
||||
*
|
||||
* @return Crawler A Crawler instance with the children nodes
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function children()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return new static($this->sibling($this->getNode(0)->firstChild), $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute value of the first node of the list.
|
||||
*
|
||||
* @param string $attribute The attribute name
|
||||
*
|
||||
* @return string The attribute value
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function attr($attribute)
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return $this->getNode(0)->getAttribute($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node value of the first node of the list.
|
||||
*
|
||||
* @return string The node value
|
||||
*
|
||||
* @throws \InvalidArgumentException When current node is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function text()
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
return $this->getNode(0)->nodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts information from the list of nodes.
|
||||
*
|
||||
* You can extract attributes or/and the node value (_text).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $crawler->filter('h1 a')->extract(array('_text', 'href'));
|
||||
*
|
||||
* @param array $attributes An array of attributes
|
||||
*
|
||||
* @return array An array of extracted values
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function extract($attributes)
|
||||
{
|
||||
$attributes = (array) $attributes;
|
||||
|
||||
$data = array();
|
||||
foreach ($this as $node) {
|
||||
$elements = array();
|
||||
foreach ($attributes as $attribute) {
|
||||
if ('_text' === $attribute) {
|
||||
$elements[] = $node->nodeValue;
|
||||
} else {
|
||||
$elements[] = $node->getAttribute($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
$data[] = count($attributes) > 1 ? $elements : $elements[0];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of nodes with an XPath expression.
|
||||
*
|
||||
* @param string $xpath An XPath expression
|
||||
*
|
||||
* @return Crawler A new instance of Crawler with the filtered list of nodes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function filterXPath($xpath)
|
||||
{
|
||||
$document = new \DOMDocument('1.0', 'UTF-8');
|
||||
$root = $document->appendChild($document->createElement('_root'));
|
||||
foreach ($this as $node) {
|
||||
$root->appendChild($document->importNode($node, true));
|
||||
}
|
||||
|
||||
$domxpath = new \DOMXPath($document);
|
||||
|
||||
return new static($domxpath->query($xpath), $this->uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of nodes with a CSS selector.
|
||||
*
|
||||
* This method only works if you have installed the CssSelector Symfony Component.
|
||||
*
|
||||
* @param string $selector A CSS selector
|
||||
*
|
||||
* @return Crawler A new instance of Crawler with the filtered list of nodes
|
||||
*
|
||||
* @throws \RuntimeException if the CssSelector Component is not available
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function filter($selector)
|
||||
{
|
||||
if (!class_exists('Symfony\\Component\\CssSelector\\CssSelector')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector is not installed (you can use filterXPath instead).');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $this->filterXPath(CssSelector::toXPath($selector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects links by name or alt value for clickable images.
|
||||
*
|
||||
* @param string $value The link text
|
||||
*
|
||||
* @return Crawler A new instance of Crawler with the filtered list of nodes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function selectLink($value)
|
||||
{
|
||||
$xpath = sprintf('//a[contains(concat(\' \', normalize-space(string(.)), \' \'), %s)] ', static::xpathLiteral(' '.$value.' ')).
|
||||
sprintf('| //a/img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)]/ancestor::a', static::xpathLiteral(' '.$value.' '));
|
||||
|
||||
return $this->filterXPath($xpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a button by name or alt value for images.
|
||||
*
|
||||
* @param string $value The button text
|
||||
*
|
||||
* @return Crawler A new instance of Crawler with the filtered list of nodes
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function selectButton($value)
|
||||
{
|
||||
$xpath = sprintf('//input[((@type="submit" or @type="button") and contains(concat(\' \', normalize-space(string(@value)), \' \'), %s)) ', static::xpathLiteral(' '.$value.' ')).
|
||||
sprintf('or (@type="image" and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)) or @id="%s" or @name="%s"] ', static::xpathLiteral(' '.$value.' '), $value, $value).
|
||||
sprintf('| //button[contains(concat(\' \', normalize-space(string(.)), \' \'), %s) or @id="%s" or @name="%s"]', static::xpathLiteral(' '.$value.' '), $value, $value);
|
||||
|
||||
return $this->filterXPath($xpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Link object for the first node in the list.
|
||||
*
|
||||
* @param string $method The method for the link (get by default)
|
||||
*
|
||||
* @return Link A Link instance
|
||||
*
|
||||
* @throws \InvalidArgumentException If the current node list is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function link($method = 'get')
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
$node = $this->getNode(0);
|
||||
|
||||
return new Link($node, $this->uri, $method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of Link objects for the nodes in the list.
|
||||
*
|
||||
* @return array An array of Link instances
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function links()
|
||||
{
|
||||
$links = array();
|
||||
foreach ($this as $node) {
|
||||
$links[] = new Link($node, $this->uri, 'get');
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Form object for the first node in the list.
|
||||
*
|
||||
* @param array $values An array of values for the form fields
|
||||
* @param string $method The method for the form
|
||||
*
|
||||
* @return Form A Form instance
|
||||
*
|
||||
* @throws \InvalidArgumentException If the current node list is empty
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function form(array $values = null, $method = null)
|
||||
{
|
||||
if (!count($this)) {
|
||||
throw new \InvalidArgumentException('The current node list is empty.');
|
||||
}
|
||||
|
||||
$form = new Form($this->getNode(0), $this->uri, $method);
|
||||
|
||||
if (null !== $values) {
|
||||
$form->setValues($values);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string for XPath expressions.
|
||||
*
|
||||
* Escaped characters are: quotes (") and apostrophe (').
|
||||
*
|
||||
* Examples:
|
||||
* <code>
|
||||
* echo Crawler::xpathLiteral('foo " bar');
|
||||
* //prints 'foo " bar'
|
||||
*
|
||||
* echo Crawler::xpathLiteral("foo ' bar");
|
||||
* //prints "foo ' bar"
|
||||
*
|
||||
* echo Crawler::xpathLiteral('a\'b"c');
|
||||
* //prints concat('a', "'", 'b"c')
|
||||
* </code>
|
||||
*
|
||||
* @param string $s String to be escaped
|
||||
*
|
||||
* @return string Converted string
|
||||
*
|
||||
*/
|
||||
public static function xpathLiteral($s)
|
||||
{
|
||||
if (false === strpos($s, "'")) {
|
||||
return sprintf("'%s'", $s);
|
||||
}
|
||||
|
||||
if (false === strpos($s, '"')) {
|
||||
return sprintf('"%s"', $s);
|
||||
}
|
||||
|
||||
$string = $s;
|
||||
$parts = array();
|
||||
while (true) {
|
||||
if (false !== $pos = strpos($string, "'")) {
|
||||
$parts[] = sprintf("'%s'", substr($string, 0, $pos));
|
||||
$parts[] = "\"'\"";
|
||||
$string = substr($string, $pos + 1);
|
||||
} else {
|
||||
$parts[] = "'$string'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf("concat(%s)", implode($parts, ', '));
|
||||
}
|
||||
|
||||
private function getNode($position)
|
||||
{
|
||||
foreach ($this as $i => $node) {
|
||||
if ($i == $position) {
|
||||
return $node;
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
}
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
private function sibling($node, $siblingDir = 'nextSibling')
|
||||
{
|
||||
$nodes = array();
|
||||
|
||||
do {
|
||||
if ($node !== $this->getNode(0) && $node->nodeType === 1) {
|
||||
$nodes[] = $node;
|
||||
}
|
||||
} while ($node = $node->$siblingDir);
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DomCrawler;
|
||||
|
||||
/**
|
||||
* Link represents an HTML link (an HTML a tag).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Link
|
||||
{
|
||||
/**
|
||||
* @var \DOMNode A \DOMNode instance
|
||||
*/
|
||||
protected $node;
|
||||
/**
|
||||
* @var string The method to use for the link
|
||||
*/
|
||||
protected $method;
|
||||
/**
|
||||
* @var string The URI of the page where the link is embedded (or the base href)
|
||||
*/
|
||||
protected $currentUri;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \DOMNode $node A \DOMNode instance
|
||||
* @param string $currentUri The URI of the page where the link is embedded (or the base href)
|
||||
* @param string $method The method to use for the link (get by default)
|
||||
*
|
||||
* @throws \InvalidArgumentException if the node is not a link
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct(\DOMNode $node, $currentUri, $method = 'GET')
|
||||
{
|
||||
if (!in_array(substr($currentUri, 0, 4), array('http', 'file'))) {
|
||||
throw new \InvalidArgumentException(sprintf('Current URI must be an absolute URL ("%s").', $currentUri));
|
||||
}
|
||||
|
||||
$this->setNode($node);
|
||||
$this->method = $method ? strtoupper($method) : null;
|
||||
$this->currentUri = $currentUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the node associated with this link.
|
||||
*
|
||||
* @return \DOMNode A \DOMNode instance
|
||||
*/
|
||||
public function getNode()
|
||||
{
|
||||
return $this->node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the method associated with this link.
|
||||
*
|
||||
* @return string The method
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI associated with this link.
|
||||
*
|
||||
* @return string The URI
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function getUri()
|
||||
{
|
||||
$uri = trim($this->getRawUri());
|
||||
|
||||
// absolute URL?
|
||||
if (0 === strpos($uri, 'http')) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
// empty URI
|
||||
if (!$uri) {
|
||||
return $this->currentUri;
|
||||
}
|
||||
|
||||
// only an anchor
|
||||
if ('#' === $uri[0]) {
|
||||
$baseUri = $this->currentUri;
|
||||
if (false !== $pos = strpos($baseUri, '#')) {
|
||||
$baseUri = substr($baseUri, 0, $pos);
|
||||
}
|
||||
|
||||
return $baseUri.$uri;
|
||||
}
|
||||
|
||||
// only a query string
|
||||
if ('?' === $uri[0]) {
|
||||
$baseUri = $this->currentUri;
|
||||
|
||||
// remove the query string from the current uri
|
||||
if (false !== $pos = strpos($baseUri, '?')) {
|
||||
$baseUri = substr($baseUri, 0, $pos);
|
||||
}
|
||||
|
||||
return $baseUri.$uri;
|
||||
}
|
||||
|
||||
// absolute path
|
||||
if ('/' === $uri[0]) {
|
||||
return preg_replace('#^(.*?//[^/]+)(?:\/.*)?$#', '$1', $this->currentUri).$uri;
|
||||
}
|
||||
|
||||
// relative path
|
||||
return substr($this->currentUri, 0, strrpos($this->currentUri, '/') + 1).$uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns raw uri data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRawUri()
|
||||
{
|
||||
return $this->node->getAttribute('href');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current \DOMNode instance
|
||||
*
|
||||
* @param \DOMNode $node A \DOMNode instance
|
||||
*
|
||||
* @throws \LogicException If given node is not an anchor
|
||||
*/
|
||||
protected function setNode(\DOMNode $node)
|
||||
{
|
||||
if ('a' != $node->nodeName) {
|
||||
throw new \LogicException(sprintf('Unable to click on a "%s" tag.', $node->nodeName));
|
||||
}
|
||||
|
||||
$this->node = $node;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
/* Configure session cache */
|
||||
session_cache_limiter('nocache');
|
||||
session_start();
|
||||
|
||||
include_once "gda-utils.php";
|
||||
include_once "gda-config.php";
|
||||
|
||||
header('Content-type: text/plain; charset=UTF-8');
|
||||
|
||||
$cmdfile = get_command_filename (session_id ());
|
||||
$replyfile = get_reply_filename (session_id ());
|
||||
|
||||
@unlink ($cmdfile);
|
||||
@unlink ($replyfile);
|
||||
|
||||
/* all cleaned */
|
||||
$reply = new SimpleXMLElement("<reply></reply>");
|
||||
$reply->addChild ("status", "OK");
|
||||
echo gda_add_hash ($init_shared, $reply->asXml());
|
||||
session_destroy ();
|
||||
|
||||
?>
|
||||
@@ -1,238 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is standalone Firefox Windows performance test.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Google Inc.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2006
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Alice Nodelman <anodelman@mozilla.com> (original author)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
__author__ = 'anodelman@mozilla.com (Alice Nodelman)'
|
||||
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import threading
|
||||
import platform
|
||||
from ffprocess_linux import LinuxProcess
|
||||
from ffprocess_mac import MacProcess
|
||||
from ffprocess_win32 import Win32Process
|
||||
from utils import talosError
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
import stat
|
||||
|
||||
|
||||
if platform.system() == "Linux":
|
||||
platform_type = 'linux_'
|
||||
ffprocess = LinuxProcess()
|
||||
elif platform.system() in ("Windows", "Microsoft"):
|
||||
import win32pdh
|
||||
import win32api
|
||||
import win32event
|
||||
import win32con
|
||||
platform_type = 'win_'
|
||||
ffprocess = Win32Process()
|
||||
elif platform.system() == "Darwin":
|
||||
platform_type = 'mac_'
|
||||
ffprocess = MacProcess()
|
||||
|
||||
class BrowserWaiter(threading.Thread):
|
||||
|
||||
def __init__(self, command, log, mod, deviceManager = None):
|
||||
self.command = command
|
||||
self.log = log
|
||||
self.mod = mod
|
||||
self.endTime = -1
|
||||
self.returncode = -1
|
||||
self.deviceManager = deviceManager
|
||||
threading.Thread.__init__(self)
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
if self.mod:
|
||||
if (self.deviceManager.__class__.__name__ == "WinmoProcess"):
|
||||
if (self.mod == "str(int(time.time()*1000))"):
|
||||
self.command += self.deviceManager.getCurrentTime()
|
||||
else:
|
||||
self.command = self.command + eval(self.mod)
|
||||
|
||||
if (self.deviceManager.__class__.__name__ == "WinmoProcess"):
|
||||
retVal = self.deviceManager.launchProcess(self.command, timeout=600)
|
||||
if retVal <> None:
|
||||
self.deviceManager.getFile(retVal, self.log)
|
||||
self.returncode = 0
|
||||
else:
|
||||
self.returncode = 1
|
||||
else: #blocking call to system
|
||||
self.returncode = os.system(self.command + " > " + self.log)
|
||||
|
||||
self.endTime = int(time.time()*1000)
|
||||
|
||||
def hasTime(self):
|
||||
return self.endTime > -1
|
||||
|
||||
def getTime(self):
|
||||
return self.endTime
|
||||
|
||||
def getReturn(self):
|
||||
def innerMethod(self):
|
||||
pass
|
||||
return self.returncode
|
||||
|
||||
def testMethod2(self):
|
||||
class InnerClass:
|
||||
def innerInnerMethod(self):
|
||||
pass
|
||||
return
|
||||
|
||||
class Test:
|
||||
def testMethod(self):
|
||||
pass
|
||||
|
||||
class BrowserController:
|
||||
|
||||
def __init__(self, command, mod, name, child_process,
|
||||
timeout, log, host='', port=20701, root=''):
|
||||
global ffprocess
|
||||
self.command = command
|
||||
self.mod = mod
|
||||
self.process_name = name
|
||||
self.child_process = child_process
|
||||
self.browser_wait = timeout
|
||||
self.log = log
|
||||
self.timeout = 1200 #no output from the browser in 20 minutes = failure
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.root = root
|
||||
if (host <> ''):
|
||||
from ffprocess_winmo import WinmoProcess
|
||||
platform_type = 'win_'
|
||||
ffprocess = WinmoProcess(host, port, root)
|
||||
|
||||
self.ffprocess = ffprocess
|
||||
|
||||
def run(self):
|
||||
self.bwaiter = BrowserWaiter(self.command, self.log, self.mod, self.ffprocess)
|
||||
noise = 0
|
||||
prev_size = 0
|
||||
while not self.bwaiter.hasTime():
|
||||
if noise > self.timeout: # check for frozen browser
|
||||
try:
|
||||
ffprocess.cleanupProcesses(self.process_name, self.child_process, self.browser_wait)
|
||||
except talosError, te:
|
||||
os.abort() #kill myself off because something horrible has happened
|
||||
os.chmod(self.log, 0777)
|
||||
results_file = open(self.log, "a")
|
||||
results_file.write("\n__FAILbrowser frozen__FAIL\n")
|
||||
results_file.close()
|
||||
return
|
||||
time.sleep(1)
|
||||
try:
|
||||
open(self.log, "r").close() #HACK FOR WINDOWS: refresh the file information
|
||||
size = os.path.getsize(self.log)
|
||||
except:
|
||||
size = 0
|
||||
|
||||
if size > prev_size:
|
||||
prev_size = size
|
||||
noise = 0
|
||||
else:
|
||||
noise += 1
|
||||
|
||||
results_file = open(self.log, "a")
|
||||
if self.bwaiter.getReturn() != 0: #the browser shutdown, but not cleanly
|
||||
results_file.write("\n__FAILbrowser non-zero return code (%d)__FAIL\n" % self.bwaiter.getReturn())
|
||||
return
|
||||
results_file.write("__startSecondTimestamp%d__endSecondTimestamp\n" % self.bwaiter.getTime())
|
||||
results_file.close()
|
||||
return
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
|
||||
command = ""
|
||||
name = "firefox" #default
|
||||
child_process = "plugin-container" #default
|
||||
timeout = ""
|
||||
log = ""
|
||||
mod = ""
|
||||
host = ""
|
||||
deviceRoot = ""
|
||||
port = 20701
|
||||
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
opts, args = getopt.getopt(argv[1:], "c:t:n:p:l:m:h:r:o", ["command=", "timeout=", "name=", "child_process=", "log=", "mod=", "host=", "deviceRoot=", "port="])
|
||||
|
||||
# option processing
|
||||
for option, value in opts:
|
||||
if option in ("-c", "--command"):
|
||||
command = value
|
||||
if option in ("-t", "--timeout"):
|
||||
timeout = int(value)
|
||||
if option in ("-n", "--name"):
|
||||
name = value
|
||||
if option in ("-p", "--child_process"):
|
||||
child_process = value
|
||||
if option in ("-l", "--log"):
|
||||
log = value
|
||||
if option in ("-m", "--mod"):
|
||||
mod = value
|
||||
if option in ("-h", "--host"):
|
||||
host = value
|
||||
if option in ("-r", "--deviceRoot"):
|
||||
deviceRoot = value
|
||||
if option in ("-o", "--port"):
|
||||
port = value
|
||||
|
||||
if command and timeout and log:
|
||||
bcontroller = BrowserController(command, mod, name, child_process, timeout, log, host, port, deviceRoot)
|
||||
bcontroller.run()
|
||||
else:
|
||||
print "\nFAIL: no command\n"
|
||||
sys.stdout.flush()
|
||||
|
||||
class mainClass:
|
||||
def mainClassMethod(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
def mainMethod(self):
|
||||
class mainMethodClass:
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,697 +0,0 @@
|
||||
"""
|
||||
Makefile functions.
|
||||
"""
|
||||
|
||||
import parser, util
|
||||
import subprocess, os, logging
|
||||
from globrelative import glob
|
||||
from cStringIO import StringIO
|
||||
|
||||
log = logging.getLogger('pymake.data')
|
||||
|
||||
class Function(object):
|
||||
"""
|
||||
An object that represents a function call. This class is always subclassed
|
||||
with the following methods and attributes:
|
||||
|
||||
minargs = minimum # of arguments
|
||||
maxargs = maximum # of arguments (0 means unlimited)
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting)
|
||||
Calls the function
|
||||
calls fd.write() with strings
|
||||
"""
|
||||
|
||||
__slots__ = ('_arguments', 'loc')
|
||||
|
||||
def __init__(self, loc):
|
||||
self._arguments = []
|
||||
self.loc = loc
|
||||
assert self.minargs > 0
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._arguments[key]
|
||||
|
||||
def setup(self):
|
||||
argc = len(self._arguments)
|
||||
|
||||
if argc < self.minargs:
|
||||
raise data.DataError("Not enough arguments to function %s, requires %s" % (self.name, self.minargs), self.loc)
|
||||
|
||||
assert self.maxargs == 0 or argc <= self.maxargs, "Parser screwed up, gave us too many args"
|
||||
|
||||
def append(self, arg):
|
||||
assert isinstance(arg, (data.Expansion, data.StringExpansion))
|
||||
self._arguments.append(arg)
|
||||
|
||||
def __len__(self):
|
||||
return len(self._arguments)
|
||||
|
||||
class VariableRef(Function):
|
||||
__slots__ = ('vname', 'loc')
|
||||
|
||||
def __init__(self, loc, vname):
|
||||
self.loc = loc
|
||||
assert isinstance(vname, (data.Expansion, data.StringExpansion))
|
||||
self.vname = vname
|
||||
|
||||
def setup(self):
|
||||
assert False, "Shouldn't get here"
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
vname = self.vname.resolvestr(makefile, variables, setting)
|
||||
if vname in setting:
|
||||
raise data.DataError("Setting variable '%s' recursively references itself." % (vname,), self.loc)
|
||||
|
||||
flavor, source, value = variables.get(vname)
|
||||
if value is None:
|
||||
log.debug("%s: variable '%s' was not set" % (self.loc, vname))
|
||||
return
|
||||
|
||||
value.resolve(makefile, variables, fd, setting + [vname])
|
||||
|
||||
class SubstitutionRef(Function):
|
||||
"""$(VARNAME:.c=.o) and $(VARNAME:%.c=%.o)"""
|
||||
|
||||
__slots__ = ('loc', 'vname', 'substfrom', 'substto')
|
||||
|
||||
def __init__(self, loc, varname, substfrom, substto):
|
||||
self.loc = loc
|
||||
self.vname = varname
|
||||
self.substfrom = substfrom
|
||||
self.substto = substto
|
||||
|
||||
def setup(self):
|
||||
assert False, "Shouldn't get here"
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
vname = self.vname.resolvestr(makefile, variables, setting)
|
||||
if vname in setting:
|
||||
raise data.DataError("Setting variable '%s' recursively references itself." % (vname,), self.loc)
|
||||
|
||||
substfrom = self.substfrom.resolvestr(makefile, variables, setting)
|
||||
substto = self.substto.resolvestr(makefile, variables, setting)
|
||||
|
||||
flavor, source, value = variables.get(vname)
|
||||
if value is None:
|
||||
log.debug("%s: variable '%s' was not set" % (self.loc, vname))
|
||||
return
|
||||
|
||||
f = data.Pattern(substfrom)
|
||||
if not f.ispattern():
|
||||
f = data.Pattern('%' + substfrom)
|
||||
substto = '%' + substto
|
||||
|
||||
fd.write(' '.join([f.subst(substto, word, False)
|
||||
for word in value.resolvesplit(makefile, variables, setting + [vname])]))
|
||||
|
||||
class SubstFunction(Function):
|
||||
name = 'subst'
|
||||
minargs = 3
|
||||
maxargs = 3
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
s = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
r = self._arguments[1].resolvestr(makefile, variables, setting)
|
||||
d = self._arguments[2].resolvestr(makefile, variables, setting)
|
||||
fd.write(d.replace(s, r))
|
||||
|
||||
class PatSubstFunction(Function):
|
||||
name = 'patsubst'
|
||||
minargs = 3
|
||||
maxargs = 3
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
s = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
r = self._arguments[1].resolvestr(makefile, variables, setting)
|
||||
|
||||
p = data.Pattern(s)
|
||||
fd.write(' '.join([p.subst(r, word, False)
|
||||
for word in self._arguments[2].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class StripFunction(Function):
|
||||
name = 'strip'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
util.joiniter(fd, self._arguments[0].resolvesplit(makefile, variables, setting))
|
||||
|
||||
class FindstringFunction(Function):
|
||||
name = 'findstring'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
s = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
r = self._arguments[1].resolvestr(makefile, variables, setting)
|
||||
if r.find(s) == -1:
|
||||
return
|
||||
fd.write(s)
|
||||
|
||||
class FilterFunction(Function):
|
||||
name = 'filter'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
plist = [data.Pattern(p)
|
||||
for p in self._arguments[0].resolvesplit(makefile, variables, setting)]
|
||||
|
||||
fd.write(' '.join([w for w in self._arguments[1].resolvesplit(makefile, variables, setting)
|
||||
if util.any((p.match(w) for p in plist))]))
|
||||
|
||||
class FilteroutFunction(Function):
|
||||
name = 'filter-out'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
plist = [data.Pattern(p)
|
||||
for p in self._arguments[0].resolvesplit(makefile, variables, setting)]
|
||||
|
||||
fd.write(' '.join([w for w in self._arguments[1].resolvesplit(makefile, variables, setting)
|
||||
if not util.any((p.match(w) for p in plist))]))
|
||||
|
||||
class SortFunction(Function):
|
||||
name = 'sort'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
d = list(self._arguments[0].resolvesplit(makefile, variables, setting))
|
||||
d.sort()
|
||||
util.joiniter(fd, d)
|
||||
|
||||
class WordFunction(Function):
|
||||
name = 'word'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
n = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
# TODO: provide better error if this doesn't convert
|
||||
n = int(n)
|
||||
words = list(self._arguments[1].resolvesplit(makefile, variables, setting))
|
||||
if n < 1 or n > len(words):
|
||||
return
|
||||
fd.write(words[n - 1])
|
||||
|
||||
class WordlistFunction(Function):
|
||||
name = 'wordlist'
|
||||
minargs = 3
|
||||
maxargs = 3
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
nfrom = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
nto = self._arguments[1].resolvestr(makefile, variables, setting)
|
||||
# TODO: provide better errors if this doesn't convert
|
||||
nfrom = int(nfrom)
|
||||
nto = int(nto)
|
||||
|
||||
words = list(self._arguments[2].resolvesplit(makefile, variables, setting))
|
||||
|
||||
if nfrom < 1:
|
||||
nfrom = 1
|
||||
if nto < 1:
|
||||
nto = 1
|
||||
|
||||
util.joiniter(fd, words[nfrom - 1:nto])
|
||||
|
||||
class WordsFunction(Function):
|
||||
name = 'words'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
fd.write(str(len(self._arguments[0].resolvesplit(makefile, variables, setting))))
|
||||
|
||||
class FirstWordFunction(Function):
|
||||
name = 'firstword'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
l = self._arguments[0].resolvesplit(makefile, variables, setting)
|
||||
if len(l):
|
||||
fd.write(l[0])
|
||||
|
||||
class LastWordFunction(Function):
|
||||
name = 'lastword'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
l = self._arguments[0].resolvesplit(makefile, variables, setting)
|
||||
if len(l):
|
||||
fd.write(l[-1])
|
||||
|
||||
def pathsplit(path, default='./'):
|
||||
"""
|
||||
Splits a path into dirpart, filepart on the last slash. If there is no slash, dirpart
|
||||
is ./
|
||||
"""
|
||||
dir, slash, file = util.strrpartition(path, '/')
|
||||
if dir == '':
|
||||
return default, file
|
||||
|
||||
return dir + slash, file
|
||||
|
||||
class DirFunction(Function):
|
||||
name = 'dir'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
fd.write(' '.join([pathsplit(path)[0]
|
||||
for path in self._arguments[0].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class NotDirFunction(Function):
|
||||
name = 'notdir'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
fd.write(' '.join([pathsplit(path)[1]
|
||||
for path in self._arguments[0].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class SuffixFunction(Function):
|
||||
name = 'suffix'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
@staticmethod
|
||||
def suffixes(words):
|
||||
for w in words:
|
||||
dir, file = pathsplit(w)
|
||||
base, dot, suffix = util.strrpartition(file, '.')
|
||||
if base != '':
|
||||
yield dot + suffix
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
util.joiniter(fd, self.suffixes(self._arguments[0].resolvesplit(makefile, variables, setting)))
|
||||
|
||||
class BasenameFunction(Function):
|
||||
name = 'basename'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
@staticmethod
|
||||
def basenames(words):
|
||||
for w in words:
|
||||
dir, file = pathsplit(w, '')
|
||||
base, dot, suffix = util.strrpartition(file, '.')
|
||||
if dot == '':
|
||||
base = suffix
|
||||
|
||||
yield dir + base
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
util.joiniter(fd, self.basenames(self._arguments[0].resolvesplit(makefile, variables, setting)))
|
||||
|
||||
class AddSuffixFunction(Function):
|
||||
name = 'addprefix'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
suffix = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
fd.write(' '.join([w + suffix for w in self._arguments[1].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class AddPrefixFunction(Function):
|
||||
name = 'addsuffix'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
prefix = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
fd.write(' '.join([prefix + w for w in self._arguments[1].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class JoinFunction(Function):
|
||||
name = 'join'
|
||||
minargs = 2
|
||||
maxargs = 2
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
@staticmethod
|
||||
def iterjoin(l1, l2):
|
||||
for i in xrange(0, max(len(l1), len(l2))):
|
||||
i1 = i < len(l1) and l1[i] or ''
|
||||
i2 = i < len(l2) and l2[i] or ''
|
||||
yield i1 + i2
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
list1 = list(self._arguments[0].resolvesplit(makefile, variables, setting))
|
||||
list2 = list(self._arguments[1].resolvesplit(makefile, variables, setting))
|
||||
|
||||
util.joiniter(fd, self.iterjoin(list1, list2))
|
||||
|
||||
class WildcardFunction(Function):
|
||||
name = 'wildcard'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
patterns = self._arguments[0].resolvesplit(makefile, variables, setting)
|
||||
|
||||
fd.write(' '.join([x.replace('\\','/')
|
||||
for p in patterns
|
||||
for x in glob(makefile.workdir, p)]))
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
class RealpathFunction(Function):
|
||||
name = 'realpath'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
fd.write(' '.join([os.path.realpath(os.path.join(makefile.workdir, path)).replace('\\', '/')
|
||||
for path in self._arguments[0].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class AbspathFunction(Function):
|
||||
name = 'abspath'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
assert os.path.isabs(makefile.workdir)
|
||||
fd.write(' '.join([util.normaljoin(makefile.workdir, path).replace('\\', '/')
|
||||
for path in self._arguments[0].resolvesplit(makefile, variables, setting)]))
|
||||
|
||||
class IfFunction(Function):
|
||||
name = 'if'
|
||||
minargs = 1
|
||||
maxargs = 3
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def setup(self):
|
||||
Function.setup(self)
|
||||
self._arguments[0].lstrip()
|
||||
self._arguments[0].rstrip()
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
condition = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
if len(condition):
|
||||
self._arguments[1].resolve(makefile, variables, fd, setting)
|
||||
elif len(self._arguments) > 2:
|
||||
return self._arguments[2].resolve(makefile, variables, fd, setting)
|
||||
|
||||
class OrFunction(Function):
|
||||
name = 'or'
|
||||
minargs = 1
|
||||
maxargs = 0
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
for arg in self._arguments:
|
||||
r = arg.resolvestr(makefile, variables, setting)
|
||||
if r != '':
|
||||
fd.write(r)
|
||||
return
|
||||
|
||||
class AndFunction(Function):
|
||||
name = 'and'
|
||||
minargs = 1
|
||||
maxargs = 0
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
r = ''
|
||||
|
||||
for arg in self._arguments:
|
||||
r = arg.resolvestr(makefile, variables, setting)
|
||||
if r == '':
|
||||
return
|
||||
|
||||
fd.write(r)
|
||||
|
||||
class ForEachFunction(Function):
|
||||
name = 'foreach'
|
||||
minargs = 3
|
||||
maxargs = 3
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
vname = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
e = self._arguments[2]
|
||||
|
||||
v = data.Variables(parent=variables)
|
||||
firstword = True
|
||||
|
||||
for w in self._arguments[1].resolvesplit(makefile, variables, setting):
|
||||
if firstword:
|
||||
firstword = False
|
||||
else:
|
||||
fd.write(' ')
|
||||
|
||||
v.set(vname, data.Variables.FLAVOR_SIMPLE, data.Variables.SOURCE_AUTOMATIC, w)
|
||||
e.resolve(makefile, v, fd, setting)
|
||||
|
||||
class CallFunction(Function):
|
||||
name = 'call'
|
||||
minargs = 1
|
||||
maxargs = 0
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
vname = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
if vname in setting:
|
||||
raise data.DataError("Recursively setting variable '%s'" % (vname,))
|
||||
|
||||
v = data.Variables(parent=variables)
|
||||
v.set('0', data.Variables.FLAVOR_SIMPLE, data.Variables.SOURCE_AUTOMATIC, vname)
|
||||
for i in xrange(1, len(self._arguments)):
|
||||
param = self._arguments[i].resolvestr(makefile, variables, setting)
|
||||
v.set(str(i), data.Variables.FLAVOR_SIMPLE, data.Variables.SOURCE_AUTOMATIC, param)
|
||||
|
||||
flavor, source, e = variables.get(vname)
|
||||
|
||||
if e is None:
|
||||
return
|
||||
|
||||
if flavor == data.Variables.FLAVOR_SIMPLE:
|
||||
log.warning("%s: calling variable '%s' which is simply-expanded" % (self.loc, vname))
|
||||
|
||||
# but we'll do it anyway
|
||||
e.resolve(makefile, v, fd, setting + [vname])
|
||||
|
||||
class ValueFunction(Function):
|
||||
name = 'value'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
varname = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
flavor, source, value = variables.get(varname, expand=False)
|
||||
if value is not None:
|
||||
fd.write(value)
|
||||
|
||||
class EvalFunction(Function):
|
||||
name = 'eval'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
if makefile.parsingfinished:
|
||||
# GNU make allows variables to be set by recursive expansion during
|
||||
# command execution. This seems really dumb to me, so I don't!
|
||||
raise data.DataError("$(eval) not allowed via recursive expansion after parsing is finished", self.loc)
|
||||
|
||||
stmts = parser.parsestring(self._arguments[0].resolvestr(makefile, variables, setting),
|
||||
'evaluation from %s' % self.loc)
|
||||
stmts.execute(makefile)
|
||||
|
||||
class OriginFunction(Function):
|
||||
name = 'origin'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
vname = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
flavor, source, value = variables.get(vname)
|
||||
if source is None:
|
||||
r = 'undefined'
|
||||
elif source == data.Variables.SOURCE_OVERRIDE:
|
||||
r = 'override'
|
||||
|
||||
elif source == data.Variables.SOURCE_MAKEFILE:
|
||||
r = 'file'
|
||||
elif source == data.Variables.SOURCE_ENVIRONMENT:
|
||||
r = 'environment'
|
||||
elif source == data.Variables.SOURCE_COMMANDLINE:
|
||||
r = 'command line'
|
||||
elif source == data.Variables.SOURCE_AUTOMATIC:
|
||||
r = 'automatic'
|
||||
elif source == data.Variables.SOURCE_IMPLICIT:
|
||||
r = 'default'
|
||||
|
||||
fd.write(r)
|
||||
|
||||
class FlavorFunction(Function):
|
||||
name = 'flavor'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
varname = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
flavor, source, value = variables.get(varname)
|
||||
if flavor is None:
|
||||
r = 'undefined'
|
||||
elif flavor == data.Variables.FLAVOR_RECURSIVE:
|
||||
r = 'recursive'
|
||||
elif flavor == data.Variables.FLAVOR_SIMPLE:
|
||||
r = 'simple'
|
||||
fd.write(r)
|
||||
|
||||
class ShellFunction(Function):
|
||||
name = 'shell'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
#TODO: call this once up-front somewhere and save the result?
|
||||
shell, msys = util.checkmsyscompat()
|
||||
cline = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
|
||||
log.debug("%s: running shell command '%s'" % (self.loc, cline))
|
||||
if msys:
|
||||
cline = [shell, "-c", cline]
|
||||
p = subprocess.Popen(cline, shell=not msys, stdout=subprocess.PIPE, cwd=makefile.workdir)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
stdout = stdout.replace('\r\n', '\n')
|
||||
if stdout.endswith('\n'):
|
||||
stdout = stdout[:-1]
|
||||
stdout = stdout.replace('\n', ' ')
|
||||
|
||||
fd.write(stdout)
|
||||
|
||||
class ErrorFunction(Function):
|
||||
name = 'error'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
v = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
raise data.DataError(v, self.loc)
|
||||
|
||||
class WarningFunction(Function):
|
||||
name = 'warning'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
v = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
log.warning(v)
|
||||
|
||||
class InfoFunction(Function):
|
||||
name = 'info'
|
||||
minargs = 1
|
||||
maxargs = 1
|
||||
|
||||
__slots__ = Function.__slots__
|
||||
|
||||
def resolve(self, makefile, variables, fd, setting):
|
||||
v = self._arguments[0].resolvestr(makefile, variables, setting)
|
||||
print v
|
||||
|
||||
functionmap = {
|
||||
'subst': SubstFunction,
|
||||
'patsubst': PatSubstFunction,
|
||||
'strip': StripFunction,
|
||||
'findstring': FindstringFunction,
|
||||
'filter': FilterFunction,
|
||||
'filter-out': FilteroutFunction,
|
||||
'sort': SortFunction,
|
||||
'word': WordFunction,
|
||||
'wordlist': WordlistFunction,
|
||||
'words': WordsFunction,
|
||||
'firstword': FirstWordFunction,
|
||||
'lastword': LastWordFunction,
|
||||
'dir': DirFunction,
|
||||
'notdir': NotDirFunction,
|
||||
'suffix': SuffixFunction,
|
||||
'basename': BasenameFunction,
|
||||
'addsuffix': AddSuffixFunction,
|
||||
'addprefix': AddPrefixFunction,
|
||||
'join': JoinFunction,
|
||||
'wildcard': WildcardFunction,
|
||||
'realpath': RealpathFunction,
|
||||
'abspath': AbspathFunction,
|
||||
'if': IfFunction,
|
||||
'or': OrFunction,
|
||||
'and': AndFunction,
|
||||
'foreach': ForEachFunction,
|
||||
'call': CallFunction,
|
||||
'value': ValueFunction,
|
||||
'eval': EvalFunction,
|
||||
'origin': OriginFunction,
|
||||
'flavor': FlavorFunction,
|
||||
'shell': ShellFunction,
|
||||
'error': ErrorFunction,
|
||||
'warning': WarningFunction,
|
||||
'info': InfoFunction,
|
||||
}
|
||||
|
||||
import data
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
class ClassName(object):
|
||||
"""docstring for ClassName"""
|
||||
def __init__(self, arg):
|
||||
super(ClassName, self).__init__()
|
||||
self.arg = arg
|
||||
def function1(self):
|
||||
foo = """
|
||||
foostring
|
||||
"""
|
||||
def function2(self):
|
||||
pass
|
||||
@@ -1,50 +0,0 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import admin
|
||||
from string import join
|
||||
from settings import MEDIA_ROOT
|
||||
|
||||
class Forum(models.Model):
|
||||
title = models.CharField(max_length=60)
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
class Thread(models.Model):
|
||||
title = models.CharField(max_length=60)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
creator = models.ForeignKey(User, blank=True, null=True)
|
||||
forum = models.ForeignKey(Forum)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.creator) + " - " + self.title
|
||||
|
||||
class Post(models.Model):
|
||||
title = models.CharField(max_length=60)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
creator = models.ForeignKey(User, blank=True, null=True)
|
||||
thread = models.ForeignKey(Thread)
|
||||
body = models.TextField(max_length=10000)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"%s - %s - %s" % (self.creator, self.thread, self.title)
|
||||
|
||||
def short(self):
|
||||
return u"%s - %s\n%s" % (self.creator, self.title, self.created.strftime("%b %d, %I:%M %p"))
|
||||
short.allow_tags = True
|
||||
|
||||
### Admin
|
||||
|
||||
class ForumAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
class ThreadAdmin(admin.ModelAdmin):
|
||||
list_display = ["title", "forum", "creator", "created"]
|
||||
list_filter = ["forum", "creator"]
|
||||
|
||||
class PostAdmin(admin.ModelAdmin):
|
||||
search_fields = ["title", "creator"]
|
||||
list_display = ["title", "thread", "creator", "created"]
|
||||
|
||||
admin.site.register(Forum, ForumAdmin)
|
||||
admin.site.register(Thread, ThreadAdmin)
|
||||
admin.site.register(Post, PostAdmin)
|
||||
@@ -1,3 +0,0 @@
|
||||
def foo(a, b, \
|
||||
c, d):
|
||||
pass
|
||||
@@ -1,3 +0,0 @@
|
||||
def find_heading(self, position=0, direction=Direction.FORWARD, \
|
||||
heading=Heading, connect_with_document=True):
|
||||
pass
|
||||
@@ -1,23 +0,0 @@
|
||||
import foo
|
||||
import bar
|
||||
|
||||
defaultdict(lambda: 0)
|
||||
classofhello = 0
|
||||
|
||||
class test(foo, bar):
|
||||
class Inner:
|
||||
# pass
|
||||
def foo(self):
|
||||
print "Inner"
|
||||
# pass
|
||||
|
||||
def test():
|
||||
class Inner2:
|
||||
def bar(self):
|
||||
print "Inner2"
|
||||
# t = Inner2()
|
||||
# pass
|
||||
|
||||
#print "Test"
|
||||
#r = test.Inner2()
|
||||
#test()
|
||||
@@ -1,3 +0,0 @@
|
||||
from test import *
|
||||
|
||||
r = test.Inner()
|
||||
@@ -1,225 +0,0 @@
|
||||
#!/usr/bin/env python2.6
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import gtk
|
||||
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
matplotlib.use('GTKAgg')
|
||||
import matplotlib.cm as cm
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.widgets import Button, RadioButtons
|
||||
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
|
||||
|
||||
win = gtk.Window()
|
||||
win.connect("destroy", gtk.main_quit)
|
||||
win.set_default_size(600,600)
|
||||
win.set_title("Resource Visualisation")
|
||||
|
||||
fig = plt.figure(figsize=(8,8))
|
||||
ax = fig.add_axes([0.1, 0.2, 0.8, 0.75], projection='polar')
|
||||
|
||||
rax = fig.add_axes([0.7, 0.05, 0.2, 0.05])
|
||||
rax.grid(False)
|
||||
rax.set_xticks([])
|
||||
rax.set_yticks([])
|
||||
|
||||
moax = fig.add_axes([0.1, 0.02, 0.25, 0.1])
|
||||
moax.grid(False)
|
||||
moax.set_xticks([])
|
||||
moax.set_yticks([])
|
||||
|
||||
logax = fig.add_axes([0.4, 0.02, 0.25, 0.1])
|
||||
logax.grid(False)
|
||||
logax.set_xticks([])
|
||||
logax.set_yticks([])
|
||||
|
||||
canvas = FigureCanvas(fig)
|
||||
win.add(canvas)
|
||||
|
||||
class ResVis(object):
|
||||
def __init__(self):
|
||||
self.dirdata = self.load_data('dirs.dat')
|
||||
self.userdata = self.load_data('users.dat')
|
||||
|
||||
self.mode = 'dir'
|
||||
self.log = True
|
||||
self.draw_dir('root')
|
||||
|
||||
def load_data(self, filename):
|
||||
data = {}
|
||||
for line in open(filename, 'r').readlines():
|
||||
entry = line.split(None, 3)
|
||||
|
||||
if len(entry) > 3: # current entry has subentries
|
||||
entry[3] = entry[3].split()
|
||||
entry[3].sort(key=str.lower)
|
||||
else:
|
||||
entry.append([])
|
||||
|
||||
data[entry[0]] = [entry[0], float(entry[1]), float(entry[2]),
|
||||
entry[3]]
|
||||
return data
|
||||
|
||||
def load_dir(self, dirname):
|
||||
curdirdata = []
|
||||
for d in self.dirdata[dirname][3]:
|
||||
curdirdata.append(self.dirdata[d])
|
||||
return curdirdata
|
||||
|
||||
def load_user(self, username):
|
||||
curdata = []
|
||||
for u in self.userdata[username][3]:
|
||||
curdata.append(self.userdata[u])
|
||||
return curdata
|
||||
|
||||
def draw_dir(self, dirname='root'):
|
||||
self.curdir = dirname
|
||||
self.reset_ax()
|
||||
ax.set_title('Directory size')
|
||||
ax.set_xlabel(dirname, weight='bold')
|
||||
|
||||
curdir = self.load_dir(dirname)
|
||||
self.draw_data(curdir)
|
||||
|
||||
def draw_user(self, username='root'):
|
||||
self.curuser = username
|
||||
self.reset_ax()
|
||||
ax.set_title('Resource usage')
|
||||
ax.set_xlabel(username, weight='bold')
|
||||
|
||||
user = self.load_user(username)
|
||||
self.draw_data(user)
|
||||
|
||||
def reset_ax(self):
|
||||
ax.cla()
|
||||
|
||||
#ax.axis('off')
|
||||
#ax.set_axis_off()
|
||||
#ax.set_yscale('log')
|
||||
ax.grid(False)
|
||||
ax.set_xticks([]) # edge
|
||||
ax.set_yticks([]) # radius
|
||||
#ax.set_xlabel('Size')
|
||||
#ax.set_ylabel('Number of files')
|
||||
|
||||
def draw_data(self, data):
|
||||
totalsize = sum(zip(*data)[1]) # get sum of subentry sizes
|
||||
unit = 1.5 * np.pi / totalsize
|
||||
|
||||
angle = 0.5 * np.pi
|
||||
if self.log:
|
||||
maxy = max(map(np.log2, zip(*data)[2]))
|
||||
else:
|
||||
maxy = max(zip(*data)[2])
|
||||
for d in data:
|
||||
relangle = unit * d[1]
|
||||
|
||||
if len(d[3]) > 0 or self.mode == 'user':
|
||||
# scale colours since the legend occupies a quarter
|
||||
scaledangle = (angle - 0.5*np.pi) * (2 / 1.5)
|
||||
colour = cm.hsv(scaledangle/(2*np.pi))
|
||||
else:
|
||||
# colour = cm.Greys(scaledangle/(2*np.pi))
|
||||
colour = "#999999"
|
||||
|
||||
if self.log:
|
||||
# take logarithm to accomodate for big differences
|
||||
y = np.log2(d[2])
|
||||
else:
|
||||
y = d[2]
|
||||
|
||||
bar = ax.bar(angle, y, width=relangle, bottom=maxy*0.2,
|
||||
color=colour, label=d[0],
|
||||
picker=True)
|
||||
angle += relangle
|
||||
|
||||
if self.mode == 'dir':
|
||||
desc = '{0}\n{1}G'.format(d[0], d[1])
|
||||
elif self.mode == 'user':
|
||||
desc = '{0}\n{1}%'.format(d[0], d[1])
|
||||
self.draw_desc(bar[0], d, desc)
|
||||
|
||||
self.draw_legend(maxy)
|
||||
|
||||
fig.canvas.draw()
|
||||
|
||||
def draw_desc(self, bar, data, text):
|
||||
# show description in center of bar
|
||||
bbox = bar.get_bbox()
|
||||
x = bbox.xmin + (bbox.xmax - bbox.xmin) / 2
|
||||
y = bbox.ymin + (bbox.ymax - bbox.ymin) / 2
|
||||
ax.text(x, y, text, horizontalalignment='center',
|
||||
verticalalignment='center', weight='bold')
|
||||
|
||||
def draw_legend(self, maxy):
|
||||
ax.annotate('', xy=(0, maxy*0.3), xytext=(0.5*np.pi, maxy*0.3),
|
||||
arrowprops=dict(
|
||||
arrowstyle='<->',
|
||||
connectionstyle='angle3,angleA=0,angleB=-90',
|
||||
linewidth=3))
|
||||
ax.annotate('', xy=(0.04*np.pi, maxy*0.35), xytext=(0.04*np.pi, maxy),
|
||||
arrowprops=dict(
|
||||
arrowstyle='<->',
|
||||
connectionstyle='arc3',
|
||||
linewidth=3))
|
||||
|
||||
if self.mode == 'dir':
|
||||
xtext = 'Size'
|
||||
ytext = 'Number of files'
|
||||
elif self.mode == 'user':
|
||||
xtext = 'Processor usage'
|
||||
ytext = 'Memory usage'
|
||||
|
||||
ax.text(0.3*np.pi, maxy*0.35, xtext, weight='normal')
|
||||
ax.text(0.06*np.pi, maxy*0.4, ytext, weight='normal', rotation=8)
|
||||
|
||||
if self.mode == 'dir':
|
||||
ax.text(0.3*np.pi, maxy*0.6, 'Grey dirs do not\nhave subdirs.')
|
||||
|
||||
def on_pick(self, event):
|
||||
clicked = event.artist.get_label()
|
||||
|
||||
if self.mode == 'dir' and len(self.dirdata[clicked][3]) > 0:
|
||||
self.draw_dir(clicked)
|
||||
elif self.mode == 'user' and len(self.userdata[clicked][3]) > 0:
|
||||
self.draw_user(clicked)
|
||||
|
||||
def on_rootclick(self, event):
|
||||
if self.mode == 'dir':
|
||||
self.draw_dir('root')
|
||||
elif self.mode == 'user':
|
||||
self.draw_user('root')
|
||||
|
||||
def on_modeclick(self, mode):
|
||||
if mode == 'Directory size':
|
||||
self.mode = 'dir'
|
||||
self.draw_dir('root')
|
||||
elif mode == 'Resource usage':
|
||||
self.mode = 'user'
|
||||
self.draw_user('root')
|
||||
|
||||
def on_logclick(self, mode):
|
||||
self.log = mode == 'Logarithmic'
|
||||
if self.mode == 'dir':
|
||||
self.draw_dir(self.curdir)
|
||||
if self.mode == 'user':
|
||||
self.draw_user(self.curuser)
|
||||
|
||||
vis = ResVis()
|
||||
|
||||
root = Button(rax, 'Home')
|
||||
root.on_clicked(vis.on_rootclick)
|
||||
mode = RadioButtons(moax, ('Directory size', 'Resource usage'))
|
||||
mode.on_clicked(vis.on_modeclick)
|
||||
log = RadioButtons(logax, ('Logarithmic', 'Linear'))
|
||||
log.on_clicked(vis.on_logclick)
|
||||
|
||||
fig.canvas.mpl_connect('pick_event', vis.on_pick)
|
||||
|
||||
#plt.show()
|
||||
|
||||
win.show_all()
|
||||
gtk.main()
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
class Class2
|
||||
def self.fun1()
|
||||
value=if foo
|
||||
bar
|
||||
end
|
||||
end
|
||||
|
||||
def self.fun2()
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user